Inauguration speech is a ceremony marking the commencement of a new term of President of America. Often, in this speech, President addresses his policies and future presidential plans. In this study, our goal is to investigate the unfound pattern in these speeches. We focus on the differences in between Republican Presidents and Democratic Presidents as well as Presidents who received graduate school education and Presidents who did not. We want to see if different educational and political backgrounds will have impacts on the topic, word length, sentence length, and emotion of their inauguration speeches.

Before we start analyzing the President inauguration speeches, we have to first install all packages we are going to use in this report.

packages.used=c("rvest", "tibble", "qdap", 
                "sentimentr", "gplots", "dplyr",
                "tm", "syuzhet", "factoextra", 
                "beeswarm", "scales", "RColorBrewer",
                "RANN", "tm", "topicmodels",'rJava')
# check packages that need to be installed.
packages.needed=setdiff(packages.used, 
                        intersect(installed.packages()[,1], 
                                  packages.used))
# install additional packages
if(length(packages.needed)>0){
  install.packages(packages.needed, dependencies = TRUE)
}
# load packages
library(ngram)
library(ggplot2)
library("rvest")
library("tibble")
library(qdap)
library(rJava)
library("sentimentr")
library("gplots")
library("dplyr")
library("tm")
library("syuzhet")
library("factoextra")
library("beeswarm")
library("scales")
library("RColorBrewer")
library("RANN")
library("topicmodels")
library(wordcloud)
library(tidytext)
source("~/Desktop/Columbia/Semester 2/ADS/Project1/wk2-TextMining/lib/plotstacked.R")
source("~/Desktop/Columbia/Semester 2/ADS/Project1/wk2-TextMining/lib/speechFuncs.R")

Step 1 - Importing speeches

Then, we are going to import our inauguration speeches from http://www.presidency.ucsb.edu/inaugurals.php. We also format the date and remove irrevalent information, which is the last row of our inaug file.

Now, we import a csv file that contain information of the president, including president’s name, term, party, date, and number of words containing in the inauguration speech.

inaug.list=read.csv("~/Desktop/Columbia/Semester 2/ADS/Project1/wk2-TextMining/data/inauglist.csv", stringsAsFactors = FALSE)

For the ease of our further investigation, we combine file inaug and inaug.list together into one single file.

inaug.list$type=c(rep("inaug", nrow(inaug.list)))
speech.list=cbind(inaug.list, inaug)

And then, we add the inauguration speech of each president into a new column called fulltext.

speech.list$fulltext=NA
for(i in seq(nrow(speech.list))) {
  text <- read_html(speech.list$urls[i]) %>% # load the page
    html_nodes(".displaytext") %>% # isloate the text
    html_text() # get the text
  speech.list$fulltext[i]=text
  # Create the file name
  filename <- paste0("~/Desktop/Columbia/Semester 2/ADS/Project1/wk2-TextMining/data/fulltext/", 
                     speech.list$type[i],
                     speech.list$File[i], "-", 
                     speech.list$Term[i], ".txt")
  sink(file = filename) %>% # open file to write 
  cat(text)  # write the file
  sink() # close the file
}

Step 2 - Data Preprocessing

Now, we begin to analyze the speech of each president. We first separate each sentence of an inauguration speech and obtain the sentiment of each sentence using get_nrc_sentiment() command, which will return sentiment of anger, anticipation, disgust, fear, joy, sadness, surprise, trust, negative, and positive. We consider “?”, “.”, “!”, “|”, and “;” as the end of each sentence. After we finish the above steps, we remove all the rows with NA value.

sentence.list=NULL
for(i in 1:nrow(speech.list)){
  sentences=sent_detect(speech.list$fulltext[i],
                        endmarks = c("?", ".", "!", "|",";")) 
  if(length(sentences)>0){
    emotions=get_nrc_sentiment(sentences)
    word.count=word_count(sentences)
    emotions=diag(1/(word.count+0.01))%*%as.matrix(emotions)
    sentence.list=rbind(sentence.list, 
                        cbind(speech.list[i,-ncol(speech.list)],
                              sentences=as.character(sentences), 
                              word.count,
                              emotions,
                              sent.id=1:length(sentences)
                              )
    )
  }
}
sentence.list=
  sentence.list%>%
  filter(!is.na(word.count))

Step 3 - Data Analytics

Let the fun part begins! In this study, we will analyze the differences in between the inauguration speeches of Democratic Presidents and Republican Presidents as well as the presidents who attended graudate school and the presidents who did not attend graudate school. We try to answer the question of what will be the differences in emotion, word length, sentence length, and topics.

First, let us select the Democratic and Republician Presidents.

democratic = speech.list$File[which(speech.list$Party=='Democratic')]
democratic.speech.ind = which(speech.list$Party=='Democratic')
democratic.sentence.ind = which(sentence.list$Party=='Democratic')
republican = speech.list$File[which(speech.list$Party=='Republican')]
republican.speech.ind = which(speech.list$Party=='Republican')
republican.sentence.ind = which(sentence.list$Party=='Republican')

Step 3.1 - Number of words in each sentence

To obtain the number of words in each sentence, we write a function called sentence.length, which will return a vector that contains the length of each sentence of a speech.

sentence.length <- function(index, df){
  speech.vec = df$fulltext
  a = strsplit(speech.vec[index], '[?!;.|]')
  res.vec = c()
  for(j in 1:length(a[[1]])){
    res.vec = cbind(res.vec, wordcount(a[[1]][[j]]))
  }
  return(res.vec)
}

Then, we apply the sentence.length function into both Democratic and Republican inauguration speeches. Since the first democratic president is Andrew Jackson as his predecessors are all democratic-republican party or Fedralist, which both parties do not exist anymore, we will only consider the presidents after President Jackson. We do not consider Whig in this study as it also doesn’t exist today.

mean.length.democratic = 0
for(i in democratic.speech.ind){
  mean.length.democratic = mean.length.democratic + mean(sentence.length(i, speech.list))
}
mean.length.democratic = mean.length.democratic/length(democratic.speech.ind)
mean.length.republican = 0
for(i in republican.speech.ind){
  mean.length.republican = mean.length.republican + mean(sentence.length(i, speech.list))
}
mean.length.republican = mean.length.republican/length(republican.speech.ind)
cat('Democratic average number of words in each sentence',(mean.length.democratic),'\n')
Democratic average number of words in each sentence 23.79952 
cat('Republican average number of words in each sentence',(mean.length.republican))
Republican average number of words in each sentence 22.30762
df.length.repvsdem = cbind(mean.length.republican,mean.length.democratic)
barplot(df.length.repvsdem)

While republican average number of words is lower than democratic(democratic = 23.79952 vs Republican = 22.30762), there isn’t a major difference in number of words in each sentence between presidents of both parties. Hence, we begin to suspect would going to graduate school has a positive impact of the average number of words in each sentence. Our hypothesis is going to graduate school may increase the probability of the use of longer sentences.

Using the information from Wikipedia, we obtain the list of presidents in both parties who did not attend graduate school. Again, we only consider presidents after Andrew Jackson. (List of Presidents: https://en.wikipedia.org/wiki/List_of_Presidents_of_the_United_States) (Education of President: https://en.wikipedia.org/wiki/List_of_Presidents_of_the_United_States_by_education)

# republican president who did not attend graduate school
no.grad.rep = c('AbrahamLincoln','UlyssesSGrant','JamesGarfield','BenjaminHarrison', 'WilliamMcKinley','TheodoreRoosevelt','WarrenGHarding','CalvinCoolidge', 'HerbertHoover','RonaldReagan','GeorgeBush','DonaldJTrump')
no.grad.rep.speech.ind = c()
for(i in no.grad.rep){
  no.grad.rep.speech.ind = c(no.grad.rep.speech.ind, which(i == speech.list$File))
}
no.grad.rep.sentence.ind = c()
for(i in no.grad.rep){
  no.grad.rep.sentence.ind = c(no.grad.rep.sentence.ind, which(i == sentence.list$File))
}
# democratic president who did not attend gradaute school
no.grad.dem = c('AndrewJackson','MartinvanBuren','JamesKPolk','JamesBuchanan',
                'GroverCleveland-I','GroverCleveland-II','HarrySTruman',
                'JohnFKennedy')
no.grad.dem.speech.ind = c()
for(i in no.grad.dem){
  no.grad.dem.speech.ind = c(no.grad.dem.speech.ind, which(i == speech.list$File))
}
no.grad.dem.sentence.ind = c()
for(i in no.grad.dem){
  no.grad.dem.sentence.ind = c(no.grad.dem.sentence.ind, which(i == sentence.list$File))
}
cat('Out of total', length(republican),'republican presidents,','number of republican presidents who did not attend graduate school:', length(no.grad.rep),'\n')
Out of total 24 republican presidents, number of republican presidents who did not attend graduate school: 12 
cat('Out of total', length(democratic),'democratic presidents,','number of democratic presidents who did not attend graduate school:', length(no.grad.dem),'\n')
Out of total 22 democratic presidents, number of democratic presidents who did not attend graduate school: 8 

From above, we notice there are more republican presidents who did not attend graduate school. This may explain why republican has an overall lower average number of words in each sentence, which may support our hypothesis of there exists a positive correlation between going to graduate school and the use of longer sentence.

To get a more accurate explanation, let’s look at the number of students who attend graduate school in different period of time. We found a dataset from Wikipedia, which provides the number of students who attended undergraduate and graduate school since 1890. (https://en.wikipedia.org/wiki/History_of_higher_education_in_the_United_States)

year. <- c(1870,1890,1910,1930,1950,1970,1990, 2009)
BA. <- c(9400,15500,37200,122500,432000,827000,1052000,1600000)
MA. <- c(NA,1000,2100,15000,58200,208000,325000,657000)
df.degree <- data.frame(year., BA., MA.)
ggplot(df.degree)+
  geom_line(aes(x=year., y=BA., col = 'Bachelor degree'))+
  geom_line(aes(x=year., y=MA., col = 'Master degree'))+
  ylab('number of student')

As we can see from the graph, there were fewer than 1000 students attending graduate school before 1890. Therefore, we hypothesize that it was much harder to attend graudate school before 1890, which means the presidents who attended graudate school before 1890 might have a better educational background and ability. The hypothesis here is attending graduate school before 1890 has a stronger impact on the tendency of using longer sentences than attending graduate school after 1890.

mean.sentence.length.no.grad.a1890 = 0
for(i in no.grad.a1890.ind){
  mean.sentence.length.no.grad.a1890 = mean.sentence.length.no.grad.a1890 + mean(sentence.length(i, speech.list))
}
mean.sentence.length.no.grad.a1890 = mean.sentence.length.no.grad.a1890/length(no.grad.a1890.ind)  
  
mean.sentence.length.grad.a1890 = 0
for(i in grad.a1890.ind){
  mean.sentence.length.grad.a1890 = mean.sentence.length.grad.a1890 + mean(sentence.length(i, speech.list))
}
mean.sentence.length.grad.a1890 = mean.sentence.length.grad.a1890/length(grad.a1890.ind)  
mean.sentence.length.no.grad.b1890 = 0
for(i in no.grad.b1890.ind){
  mean.sentence.length.no.grad.b1890 = mean.sentence.length.no.grad.b1890 + mean(sentence.length(i, speech.list))
}
mean.sentence.length.no.grad.b1890 = mean.sentence.length.no.grad.b1890/length(no.grad.a1890.ind)  
  
mean.sentence.length.grad.b1890 = 0
for(i in grad.b1890.ind){
  mean.sentence.length.grad.b1890 = mean.sentence.length.grad.b1890 + mean(sentence.length(i, speech.list))
}
mean.sentence.length.grad.b1890 = mean.sentence.length.grad.b1890/length(grad.b1890.ind)
x.b1890 = c(mean.sentence.length.grad.b1890,mean.sentence.length.no.grad.b1890)
x.a1890 = c(mean.sentence.length.grad.a1890,mean.sentence.length.no.grad.a1890)
df.ab1890 = (cbind(x.b1890,x.a1890))
rownames(df.ab1890) = c('graduate school', 'no graduate school')
barplot(df.ab1890, beside=T, col=1:2, ylab='average sentence length')
legend('topright',legend=c('graduate', 'no graduate'),col=1:2, fill = 1:2)

The left shows the average sentence length before 1890 while the right shows the average sentence length after 1890. The result agrees with our hypothesis of going to graduate school before 1890 may have a bigger impact on the tendency of the use of longer sentences. This result also shows going to graduate school after 1890 doesn’t have a significant impact on the average number of words in each sentence, which may indicate the difficulty of going to graduate decreased as there are significant higher amount of graduate student after 1890. This indicates the quality of graduate student might as well decrease causing less impact on the ability of using longer sentences. But we will not further investigate the quality of graduate school education as we would focus more on president inauguration speech in this study.

Now, we will take a look of the number of words in each sentence for each president using beeswarm().

sentence.list.sel=sentence.list%>%filter(type=="inaug", File%in%c(republican, democratic), Term==1)
sentence.list.sel$File=factor(sentence.list.sel$File)
sentence.list.sel$FileOrdered=reorder(sentence.list.sel$File, 
                                  sentence.list.sel$word.count, 
                                  mean, 
                                  order=T)
par(mar=c(4, 11, 2, 2))
beeswarm(word.count~FileOrdered, 
         data=sentence.list.sel,
         horizontal = TRUE,
         pch=16, col=alpha(brewer.pal(9, "Set1"), 0.6), 
         cex=0.55, cex.axis=0.8, cex.lab=0.8,
         spacing=5/nlevels(sentence.list.sel$FileOrdered),
         las=2, ylab="", xlab="Number of words in a sentence.",
         main="Inaugural Speeches")

This graph above further agrees with our hypothesis of presidents who attended graduate school before 1890 tend to use longer sentences as most of the presidents who use longer sentence are the presidents who attend graduate school before 1890 (presidents near the top of the list). The graph aboves also shows us the number of words in each sentence of each president.

Now, let’s take a look of the inauguration speech content of the president who used the shortest sentences, George Bush.

corpus1 = VCorpus(VectorSource(speech.list$fulltext[speech.list$File=='GeorgeBush']))
corpus1<-tm_map(corpus1, stripWhitespace)
corpus1<-tm_map(corpus1, content_transformer(tolower))
corpus1<-tm_map(corpus1, removeWords, stopwords("english"))
corpus1<-tm_map(corpus1, removeWords, character(0))
corpus1<-tm_map(corpus1, removePunctuation)
tdm.all<-TermDocumentMatrix(corpus1)
tdm.tidy=tidy(tdm.all)
tdm.overall=summarise(group_by(tdm.tidy, term), sum(count))
wordcloud(tdm.overall$term, tdm.overall$`sum(count)`,
          scale=c(5,0.5),
          max.words=100,
          min.freq=1,
          random.order=FALSE,
          rot.per=0.3,
          use.r.layout=T,
          random.color=FALSE,
          colors=brewer.pal(9,"Blues"))

As we can see from the wordcloud above, President Bush mentioned words like nation, freedom, friends, etc, whcih are topics related to american dream and faith. President Bush used ‘will’ a lot in his speech, which is very reasonable as presidents tend to express their future plan and policy in their inauguration speech.

Next, let’s look at Donald Trump’s wordcloud, who use the second shortest sentences.

corpus1 = VCorpus(VectorSource(speech.list$fulltext[speech.list$File=='DonaldJTrump']))
corpus1<-tm_map(corpus1, stripWhitespace)
corpus1<-tm_map(corpus1, content_transformer(tolower))
corpus1<-tm_map(corpus1, removeWords, stopwords("english"))
corpus1<-tm_map(corpus1, removeWords, character(0))
corpus1<-tm_map(corpus1, removePunctuation)
tdm.all<-TermDocumentMatrix(corpus1)
tdm.tidy=tidy(tdm.all)
tdm.overall=summarise(group_by(tdm.tidy, term), sum(count))
wordcloud(tdm.overall$term, tdm.overall$`sum(count)`,
          scale=c(5,0.5),
          max.words=100,
          min.freq=1,
          random.order=FALSE,
          rot.per=0.3,
          use.r.layout=T,
          random.color=FALSE,
          colors=brewer.pal(9,"Blues"))

President Trump seems to focus on topic about ‘American’ and ‘Dream’. By comparing the wordcloud of both presidents, President Bush’s inauguration seems to cover more comprehensive words as President Trump seems to focus on relatively limited word choices. Same as President Bush, President Trump also used a lot of ‘will’.

Now, let’s have a closer look of the content of their speeches. We look at the shorter sentences from inauguration speeches of both George Bush and Donald Trump.

sentence.list%>%
  filter(File=="GeorgeBush", 
         type=="inaug", 
         word.count<=5)%>%
  select(sentences)%>%sample_n(10)
sentence.list%>%
  filter(File=="DonaldJTrump", 
         type=="inaug", 
         word.count<=5)%>%
  select(sentences)%>%sample_n(10)

The left table shows the sentences with 5 words or fewer from President Bush and the right table shows that of President Trump. Both President Bush and President Trump used a lot of thank you in his shorter sentences. President Trump mentioned his core policy, American first, a lot in his speech. As we can see from above, although both presidents used a lot of short sentences, their contents are significant different. The short sentences of President Bush are about “war”, “parent”, “compromise”, and “dissension” while the short sentences of President Trump are relatively meanless, such as ‘not fail’, ‘celebration’, ‘day’, and ‘bless’.

Now, let’s investigate the presidents who use the shortest sentences in both parties.

length.all <- c()
for(i in 1:58){
  length.all = c(length.all, mean(sentence.length(i, speech.list)))
}
length.dem <- c()
for(i in democratic.speech.ind){
  length.dem =  c(length.dem, mean(sentence.length(i, speech.list)))
}
length.rep = c()
for(i in republican.speech.ind){
  length.rep =  c(length.rep, mean(sentence.length(i, speech.list)))
}
#ggplot()+
#  geom_line(aes(republican.speech.ind, length.rep, color = 'republican'))+
#  geom_line(aes(democratic.speech.ind, length.dem, color = 'democratic'))
republican[which.min(length.rep)] #GeorgeBush shortest sentence, didn't go to grad school, 64 years old
[1] "GeorgeBush"
intersect(no.grad, republican[which.min(length.rep)])
[1] "GeorgeBush"
z = length.rep
z[which.min(length.rep)] = NA
republican[which.min(z)] #DonaldJTrump second shortest sentence, didn't go to grad school, 70 years old
[1] "DonaldJTrump"
intersect(no.grad, republican[which.min(z)])
[1] "DonaldJTrump"
democratic[which.min(length.dem)] #LyndonBJohnson, 64 years old 
[1] "LyndonBJohnson"
intersect(no.grad, democratic[which.min(length.dem)]) #went to grad school
character(0)
z1 = length.dem
z1[which.min(length.dem)] = NA
democratic[which.min(z1)] #WilliamJClinton, 46 years old
[1] "WilliamJClinton"
intersect(no.grad, democratic[which.min(z1)] )
character(0)

From this part, we see both parties have a decreasing trend of number of words in each sentence. Interestingly, we found both of two republican presidents who use the shortest sentences did not attend graduate school while both of the democratic presidents who use the shortest sentences attended graduate school.

We then suspect if there is another factor affecting the length of sentences. We searched the age of the four presidents, and found president Trump was 70 years old and president Bush was 64 years old while president Clinton was 46 years old and president Johnson was 64 years old when they gave the inauguration speech. We suspect that will the length of sentence correlate to the age of the presidents. Here, we used the data from Wikipedia. (https://en.wikipedia.org/wiki/List_of_presidents_of_the_United_States_by_age)

# Presidents that use shorter sentences
age.name = c('GeorgeBush','DonaldJTrump','LyndonBJohnson','GeorgeWBush','WilliamJClinton','RonaldReagan','RichardNixon','FranklinDRoosevelt','HarrySTruman','DwightDEisenhower','BarackObama','HerbertHoover','JimmyCarter','WarrenGHarding')
# Age of the presidents that use shorter sentences
age = c(64, 70, 64, 54, 46, 69, 56, 51, 60, 62, 47, 54, 52, 55)
cat('median age of president with shorter sentence:', median(age))
median age of president with shorter sentence: 55.5

According to Wikipedia, the median age of presidents when they entered the White House is 55.6 years old, which is close to the median age of the above data we found. Hence, there is not a correlation between age and length of sentences.

Now, let’s investigate if there is a difference in number of words in each sentence between first and second term.

first.term = speech.list$File[which(speech.list$Term==1)]
first.term.ind = which(speech.list$Term==1)
second.term = speech.list$File[which(speech.list$Term==2)]
second.term.ind = which(speech.list$Term==2)
mean.first.term.sentence.length = 0
for(i in first.term.ind){
  mean.first.term.sentence.length = mean.first.term.sentence.length + mean(sentence.length(i, speech.list))
}
mean.first.term.sentence.length = mean.first.term.sentence.length/length(first.term.ind) 
mean.second.term.sentence.length = 0
for(i in second.term.ind){
  mean.second.term.sentence.length = mean.second.term.sentence.length + mean(sentence.length(i, speech.list))
}
mean.second.term.sentence.length = mean.second.term.sentence.length/length(second.term.ind) 
cat('average number of words in each sentence for first term', mean.first.term.sentence.length,'\n')
average number of words in each sentence for first term 25.64794 
cat('average number of words in each sentence for second term', mean.second.term.sentence.length,'\n')
average number of words in each sentence for second term 24.87544 

Therefore, there is not a significant difference in between inauguration speech of first and second term.

Summary: In part 3.1, we found the average sentence length for republican presidents are lower than democratic presidents, and this may due to the fact that there are fewer republican presidnets attended graduate school as compared to democratic presidents. We also found going to graduate school before 1890 has a stronger effect on length of sentences.

Step 3.2 Data Analytics - Length of each word

After analyzing sentence length of president inauguration speeches, let’s investigate the length of the word that the presidents use. Here, we predict attending graduate school may be correlated with the length of the word that a president use such that a president who attended graduate school may use a longer word.

We define a function to count the number of character in each word. Since we are interested in the average length of big words that presidents use, we do not consider words with less than five letters.

word.length <- function(index, df){
  speech.vec = df$fulltext
  a = strsplit(speech.vec[index], '\\s')
  res.vec = c()
  for(j in 1:length(a[[1]])){
    res.vec = c(res.vec, nchar(a[[1]][[j]]))
  }
  res.vec = (res.vec[res.vec > 5])
  return(res.vec)
}

Again, same as before, let’s see if there is difference in the average word length between republican and democratic presidents.

# word length of republican and democratic 
word.length.dem <- c()
for(i in democratic.speech.ind){
  word.length.dem =  c(word.length.dem, mean(word.length(i, speech.list)))
}
word.length.rep = c()
for(i in republican.speech.ind){
  word.length.rep =  c(word.length.rep, mean(word.length(i, speech.list)))
}
cat('average word length of republican presidents:', mean(word.length.rep), '\n')
average word length of republican presidents: 8.166799 
cat('average word length of democratic presidents:', mean(word.length.dem), '\n')
average word length of democratic presidents: 8.169233 

The average word length of both parties are very similar. Then, next look at whether going to graduate school has an effect on average word length.

no.grad.word.length <- 0
for(i in no.grad.a1890.ind){
  no.grad.word.length = no.grad.word.length + mean(word.length(i,speech.list))
}
no.grad.word.length = (no.grad.word.length)/length(no.grad.a1890.ind)
grad.word.length <- 0
for(i in grad.a1890.ind){
  grad.word.length = grad.word.length + mean(word.length(i,speech.list))
}
grad.word.length = (grad.word.length)/length(grad.a1890.ind)
cat('average word length of presidents who attended graduate school:',grad.word.length,'\n')
average word length of presidents who attended graduate school: 8.006391 
cat('average word length of presidents who did not attend graduate school:',no.grad.word.length,'\n')
average word length of presidents who did not attend graduate school: 8.203511 

Again, there is not a significant difference.

Summary: In part 3.2, we conclude there are not a significant difference in average word length in between the two parties as well as in between presidents who attended graduate school and presidents who did not attend graduate school.

Step 3.3 Data Analytics - Sentiment Analysis

After analyzing both word length and sentence length, let’s dig deeper and study the emotion of the inauguration speeches.

First, let’s take a look of the overall emotion of all the presidential inauguration speeches.

emo.means=colMeans(select(sentence.list, anger:trust)>0.01)
col.use=c("red2", "darkgoldenrod1", 
            "chartreuse3", "blueviolet",
            "darkgoldenrod2", "dodgerblue3", 
            "darkgoldenrod1", "darkgoldenrod1")
barplot(emo.means[order(emo.means)], las=2, col=col.use[order(emo.means)], horiz=T, main="Inaugural Speeches")

From the above graph, we see most of the presidents like to use words that are related to trust, anticipation, and joy in their inauguration speech. Then, let’s take a look to see if the proportion of each emotion changes over the history.

anger = c(); anticipation =c(); disgust=c(); fear =c(); joy=c(); sadness=c(); surprise=c();trust=c();negative=c();positive=c()
for(i in 1:58){
  ran.ind = which(sentence.list$File == speech.list$File[i])
  anger = c(anger, apply(sentence.list[ran.ind,13:22],2, mean)[1])
  anticipation = c(anticipation, apply(sentence.list[ran.ind,13:22],2, mean)[2])
  disgust = c(disgust, apply(sentence.list[ran.ind,13:22],2, mean)[3])
  fear = c(fear, apply(sentence.list[ran.ind,13:22],2, mean)[4])
  joy = c(joy, apply(sentence.list[ran.ind,13:22],2, mean)[5])
  sadness = c(sadness, apply(sentence.list[ran.ind,13:22],2, mean)[6])
  surprise = c(surprise, apply(sentence.list[ran.ind,13:22],2, mean)[7])
  trust = c(trust, apply(sentence.list[ran.ind,13:22],2, mean)[8])
  negative = c(negative, apply(sentence.list[ran.ind,13:22],2, mean)[9])
  positive = c(positive, apply(sentence.list[ran.ind,13:22],2, mean)[10])
}
ggplot()+
  geom_line(aes(x=1:58,y=anger,color='anger'))+
  geom_line(aes(x=1:58,y=anticipation,color='anticipation'))+
  geom_line(aes(x=1:58,y=disgust,color='disgust'))+
  geom_line(aes(x=1:58,y=fear,color='fear'))+
  geom_line(aes(x=1:58,y=joy,color='joy'))+
  geom_line(aes(x=1:58,y=sadness,color='sadness'))+
  geom_line(aes(x=1:58,y=surprise,color='surprise'))+
  geom_line(aes(x=1:58,y=trust,color='trust'))+
  geom_line(aes(x=1:58,y=negative,color='negative'))+
  geom_line(aes(x=1:58,y=positive,color='positive'))+
  ylab('')

The overall trending of each emotion remain relatively stable except we see a drop in ‘positive’, ‘anticipate’, and ‘trust’ words and a raise in ‘negative’, ‘fear’, ‘anger’, and ‘sadness’ words, which happened at when the inauguration speech of Abraham Lincoln was made. Presidents Lincoln led the US through Civil War, which is often described as the bloodiest war in the US. This may explain the increased in negative words within this period of time. Also, we see a raise in ‘positive’, ‘joy’, and ‘trust’ words in the inauguration speech of Harry S. Truman. President Truman led US toward the victory of World War II, which may explain the raise of the positive emotion words in his inauguration speech.

Next, we can investigate the difference in emotion expressed by presidents in both parties. We randomly select a few presidents from each party.

# Now, lets look at the emotion of some rep presidents
random.rep=c('RichardNixon','RonaldReagan','GeorgeBush','GeorgeWBush','DonaldJTrump')
par(mfrow = c(3, 2))
for(i in random.rep){
  ran.ind = which(sentence.list$File == i)
  emo.means=colMeans(select(sentence.list[ran.ind,], anger:trust)>0.01)
col.use=c("red2", "darkgoldenrod1", 
            "chartreuse3", "blueviolet",
            "darkgoldenrod2", "dodgerblue3", 
            "darkgoldenrod1", "darkgoldenrod1")
  barplot(emo.means[order(emo.means)], las=2, col=col.use[order(emo.means)], horiz=T, main=i)
}
# lets look at the emotion of some dem presidents
random.dem = c('FranklinDRoosevelt','JohnFKennedy','LyndonBJohnson','WilliamJClinton', 'BarackObama')
par(mfrow = c(3,2))

for(i in random.dem){
  ran.ind = which(sentence.list$File == i)
  emo.means=colMeans(select(sentence.list[ran.ind,], anger:trust)>0.01)
col.use=c("red2", "darkgoldenrod1", 
            "chartreuse3", "blueviolet",
            "darkgoldenrod2", "dodgerblue3", 
            "darkgoldenrod1", "darkgoldenrod1")
  barplot(emo.means[order(emo.means)], las=2, col=col.use[order(emo.means)], horiz=T, main=i)
}

Interestly, we found the emotion in the inauguration speeches of democratic presidents are very consistent while the emotion of republican presidents’ inauguration speeches varies among different presidents.

Next, we investigate the emotion of inauguration speeches between president who attended graduate school and president who did not attend graduate school.

no_grad_school = apply(sentence.list[no.grad.a1890.ind,13:22],2, mean)
grad_school = apply(sentence.list[grad.a1890.ind,13:22],2, mean) 
barplot(as.matrix(data.frame(no_grad_school,grad_school)), beside=T, col = 0:9)
legend("topleft", c("anger","anticipation","disgust","fear","joy",'sadness','surprise','trust','negative','positive'), cex=0.5, bty="n", fill=0:9)

We found presidents who attended graduate school use significantly more positive words and significantly fewer negative words. Presidents who attended graduate school tend to use more ‘trust’ related words and fewer ‘sadness’ and ‘surprise’ related words. This may raise the possibilites hypothesis of presidents who attend graduate tend to give a more positive inauguration speech. However, further investigation and data is needed for additional evidence of this prespective.

Now, we investigate the emotion of the sentences in different length.

# short sentence vs long sentence
short.ind = which(length.all[11:58] <= mean(length.all))
long.ind = which(length.all[11:58] > mean(length.all))
short = apply(sentence.list[short.ind,13:22],2, mean)
long = apply(sentence.list[long.ind,13:22],2, mean)
barplot(as.matrix(data.frame(short,long)), beside=T, col = 0:9)
legend("topleft", c("anger","anticipation","disgust","fear","joy",'sadness','surprise','trust','negative','positive'), cex=0.5, bty="n", fill=0:9)

Here, we found longer sentences tend to have fewer “negative”, “sadness”, and “fear” related words.

In summary, in 3.3, we analyzed emotion of the inauguration speeches. We found democratic presidents’ inauguration speeches have a more consistent proportion of each emotion while republican presidents’ inauguration speeches do not have a consistent pattern. Also, presidents who went to graduate school tend to give a more positive inauguration speech, and presidents who use longer sentences tend to use fewer negative words.

Part 3.4 Data Analytics: Topic Modeling

Now, we focus on unsupervise study of the speeches. We apply topic modeling into all the inauguration speeches to find the common topics in among the speeches. We then categorize each speech into a topic that it is mostly likely to be.

To do so, we first need to apply natural language processing to our data to remove some unnecessary content, such as number, extra spaces, and meaningless words. We also stem the document, which only the stem part of the word will be remained. For example, ‘supplied’ and ‘supplies’ both become ‘suppli’.

Then, we create a big of words, which is a matrix show in a dummy variable format.

dtm <- DocumentTermMatrix(docs)
#convert rownames to filenames#convert rownames to filenames
rownames(dtm) <- paste(corpus.list$type, corpus.list$File,
                       corpus.list$Term, corpus.list$sent.id, sep="_")
rowTotals <- apply(dtm , 1, sum) #Find the sum of words in each Document
dtm  <- dtm[rowTotals> 0, ]
corpus.list=corpus.list[rowTotals>0, ]

Now, we apply LDA topic modeling into our bag of words.

#Set parameters for Gibbs sampling
burnin <- 4000 # removing the first 4000 samples
iter <- 2000
thin <- 500 #choose 500th in each round, drop the 499 others
#500 is using every 500th guess because each guess is based on its previous guess. so n to n+1 won't have much difference but n and n+500th guess would be much difference and intelligent
seed <-list(2003,5,63,100001,765)
nstart <- 5
best <- TRUE
#Number of topics
k <- 10
#Run LDA using Gibbs sampling
ldaOut <-LDA(dtm, k, method="Gibbs", control=list(nstart=nstart, 
                                                 seed = seed, best=best,
                                                 burnin = burnin, iter = iter, 
                                                 thin=thin))
#write out results
#docs to topics
ldaOut.topics <- as.matrix(topics(ldaOut))
table(c(1:k, ldaOut.topics))

  1   2   3   4   5   6   7   8   9  10 
565 977 629 555 585 457 435 419 483 436 
write.csv(ldaOut.topics,file=paste("~/Desktop/Columbia/Semester 2/ADS/Project1/wk2-TextMining/out/LDAGibbs",k,"DocsToTopics.csv"))
#top 20 terms in each topic
ldaOut.terms <- as.matrix(terms(ldaOut,20))
write.csv(ldaOut.terms,file=paste("~/Desktop/Columbia/Semester 2/ADS/Project1/wk2-TextMining/out/LDAGibbs",k,"TopicsToTerms.csv"))
#probabilities associated with each topic assignment
topicProbabilities <- as.data.frame(ldaOut@gamma)
topicProbabilities$max = apply(topicProbabilities, 1, max)
write.csv(topicProbabilities,file=paste("~/Desktop/Columbia/Semester 2/ADS/Project1/wk2-TextMining/out/LDAGibbs",k,"TopicProbabilities.csv"))
# use beta distribution
terms.beta=ldaOut@beta
terms.beta=scale(terms.beta)
topics.terms=NULL
for(i in 1:k){
  topics.terms=rbind(topics.terms, ldaOut@terms[order(terms.beta[i,], decreasing = TRUE)[1:7]])
}

After we obtain the list of topic, we look at the word each topic contains and give a title to each topic. Here, we set the title name into a vector, topics.hash.

topics.hash = c('government','american dream', 'economy', 'faith', 'anticipate', 'people', 'civil right', 'patriot', 'legistration', 'peace', 'max')
corpus.list$ldatopic=as.vector(ldaOut.topics)
#corpus.list$ldahash=topics.hash[ldaOut]
colnames(topicProbabilities)=topics.hash
corpus.list.df=cbind(corpus.list, topicProbabilities)

Now, we plot our data into a heatmap to see if some presidents share very similar topics. In a heat map, the same color means represent the same probability. The redder the color is means the higher the probability.

par(mar=c(1,1,1,1))
topic.summary=tbl_df(corpus.list.df)%>%
              filter(type%in%c('inaug'), File%in%c(democratic, republican))%>%
              select(File, government:peace)%>%
              group_by(File)%>%
              summarise_each(funs(mean))
`summarise_each()` is deprecated.
Use `summarise_all()`, `summarise_at()` or `summarise_if()` instead.
To map `funs` over all variables, use `summarise_all()`
topic.summary=as.data.frame(topic.summary)
rownames(topic.summary)=topic.summary[,1]
heatmap.2(as.matrix(topic.summary[,topic.plot+1]), 
          scale = "column", key=F, 
          col = bluered(100),
          cexRow = 0.9, cexCol = 0.9, margins = c(8, 8),
          trace = "none", density.info = "none")

From the heatmap, we saw Dwight D Eisenhower(Korean War), Harry S Truman(WW II), Warren G Harding (right after WW I), and Calbin Coolidge(post WW I) mentioned the topic of ‘peace’ in their inauguration speeches. As I analyzed more about each of their presidency, I found President Eisenhower was in the office during Korean War, President Truman was elected near the very end of World War II, President Harding was in the office right after World War I, and President Coolidge was in the office during the post World War I period. This may explain why they focus to ‘peace’ related topic.

William Howard Taft, Grover Cleveland II, Ulysses S Grant, and William Mckinley mentioned the topic of ‘economy’. As we researched more about their presidential policy and history, we found President Taft was involved in dollary diplomacy, President Cleveland was overwhelmed by nation’s economic disasters-depression, President Grant was in the office during the Gilded Age, a massive industrial growth, and President Mckinley led American through the rapid economic growth. These may explain the expression of ‘economy’ related topic in their inauguration speeches.

Now, let’s investigate the topic difference in between republican and democratic.

dem.rep.table = table(corpus.list.df[,c('Party','ldatopic')])[c(1,4),]
barplot(dem.rep.table, beside = T, col=c(2,5), xlab = 'Topic')
legend('topright', legend = c('Democratic','Republican'), fill=c(2,5))

As we can see from above, republican presidents tend to cover more about topic 3, 9, and 10, which are ‘economy’, ‘legistration’, and ‘peace’ while democratic presidents tend to cover more about topic 1 and 8, which are ‘government’ and ‘patriot’.

Now, let’s investigate on the topic that presidents who attended graduate school tend to cover.

z.no.grad = corpus.list.df[c(no.grad.dem.sentence.ind, no.grad.rep.sentence.ind),c('ldatopic')]
grad.sentence.ind = (1:nrow(corpus.list.df))[-c(no.grad.dem.sentence.ind,no.grad.rep.sentence.ind)][692:nrow(corpus.list.df)]
z.grad = corpus.list.df[grad.sentence.ind,c('ldatopic')]
z.grad.table = table(z.grad)
z.no.grad.table = table(z.no.grad)
dem.rep.table = as.data.frame(cbind(z.grad.table, z.no.grad.table))
dem.rep.table

The left table shows the number of sentences in each topic of presidents who attend graduate school while the right table shows that of presidents who did not attend graudate school. As we can see from the table above, presidents who attended graduate school tend to cover topic 2 and 5 in their inauguration speech, which are ‘american dream’ and ‘anticipate’ while presidents who did not attend graduate school tend to cover topic 3, 6, and 9, which are ‘economy’, ‘people’, and ‘legistration’. This may suggest presidents who attended graduate tend to focus on the future and core value of America while the presidents who did not attend graduate school tend to focus on more pragmatic topics.

Now, let’s perform a clustering on presidents who attended graduate school and who did not attend graudate school.

presid.summary=tbl_df(corpus.list.df)%>%
  filter(type=="inaug", File%in% speech.list$File[c(grad.a1890.ind,grad.b1890.ind)])%>%
  select(File, government:peace)%>%
  group_by(File)%>%
  summarise_each(funs(mean))
`summarise_each()` is deprecated.
Use `summarise_all()`, `summarise_at()` or `summarise_if()` instead.
To map `funs` over all variables, use `summarise_all()`
presid.summary=as.data.frame(presid.summary)
rownames(presid.summary)=as.character((presid.summary[,1]))
km.res=kmeans(scale(presid.summary[,-1]), iter.max=200,
              5)
fviz_cluster(km.res, 
             stand=T, repel= TRUE,
             data = presid.summary[,-1],
             show.clust.cent=FALSE, main = 'grad')

presid.summary=tbl_df(corpus.list.df)%>%
  filter(type=="inaug", File%in% speech.list$File[c(no.grad.a1890.ind,no.grad.b1890.ind)])%>%
  select(File, government:peace)%>%
  group_by(File)%>%
  summarise_each(funs(mean))
`summarise_each()` is deprecated.
Use `summarise_all()`, `summarise_at()` or `summarise_if()` instead.
To map `funs` over all variables, use `summarise_all()`
presid.summary=as.data.frame(presid.summary)
rownames(presid.summary)=as.character((presid.summary[,1]))
km.res=kmeans(scale(presid.summary[,-1]), iter.max=200,
              5)
fviz_cluster(km.res, 
             stand=T, repel= TRUE,
             data = presid.summary[,-1],
             show.clust.cent=FALSE, main = 'no grad')

The graph in the right shows the clustering of presidents who did not attend graduate school and the graph in the left shows that of presidents who attended graduate school. As we observe the cluster plot above, we notice president from the same party tend to form it’s own cluster. For example, in ‘no grad’ cluster, all presidents in cluster 3 are democratic while all presidents in cluster 5 are republican.

Then, we think if the presidents are clustered together, this means they gave similar inauguration speeches, which suggests they might also share similar policies. Therefore, if an American supports one of the presidents in the cluster, he/she may as well supports another president in the same cluster. Hence, we found a dataset from Wikipedia that contains approval rate of all presidents since 1937. (https://en.wikipedia.org/wiki/United_States_presidential_approval_rating)

presid.summary=tbl_df(corpus.list.df)%>%
  filter(type=="inaug", File%in% speech.list$File[37:58])%>%
  select(File, government:peace)%>%
  group_by(File)%>%
  summarise_each(funs(mean))
`summarise_each()` is deprecated.
Use `summarise_all()`, `summarise_at()` or `summarise_if()` instead.
To map `funs` over all variables, use `summarise_all()`
presid.summary=as.data.frame(presid.summary)
rownames(presid.summary)=as.character((presid.summary[,1]))
km.res=kmeans(scale(presid.summary[,-1]), iter.max=200,
              5)
fviz_cluster(km.res, 
             stand=T, repel= TRUE,
             data = presid.summary[,-1],
             show.clust.cent=FALSE, main = 'presidents after 1937')

From the graph, we look at cluster 2, where there are three presidents including Richard Nixon, William Clinton, and Barack Obama. According to the historical approval rate from Wikipedia, Preisdent Nixon has an average approval rate of 49.1, President Clinton has an average approval rate of 55.1, President Obama has an average approval rate of 47.9. Also, if we look at cluster 4, where there are four presidents including George Bush, Franklin Roosevelt, Lyndon Johnson, and Donald Trump. As President Trump has just been into an office for a year, we will account him into this approval rate analysis. President Johnson has an average approval rate of 55.1, President Bush has an average approval rate of 60.9, and President Roosevelt has an average approval rate of 63. These results match our hypothesis of presidents have similar inauguration speech tend to have similar approval rate. But further analysis is required as the collection of approval rate started in 1937 meaning we only have very limited data.

Summary: In part 3.4, we applied topic modeling into the inauguration speeches, we found presidents from differents parties tend to focus on different topics and presidents who attended to graduate school also tend to focus on different topics. Furthermore, we found presidents in the same cluster tend to be in the same party and have the similar approval rate.

Conclusion

In conclusion, in this study, we showed that Republican Presidents tend to use shorter sentences as compared to Democratic Presidents, and this may due to the fact that there are fewer Republican Presidents who attended graduate school. We also showed that Presidents who attended graduate school tend to use more positive words in their inauguration speech while presidents who use longer sentences tend to use fewer negative words. Furthermore, we found that going to graduate school before 1890 may have a stronger impact in sentence length as graduate school were harder to get in before 1890. Finally, presidents from the same party tend to cover similar topics in their inauguration speech, and presidents who mention similar topics in their inauguration speech may share similar approval rate.

Reference

https://en.wikipedia.org/wiki/United_States_presidential_approval_rating https://en.wikipedia.org/wiki/List_of_presidents_of_the_United_States_by_age https://en.wikipedia.org/wiki/History_of_higher_education_in_the_United_States https://en.wikipedia.org/wiki/List_of_Presidents_of_the_United_States_by_education https://en.wikipedia.org/wiki/List_of_Presidents_of_the_United_States

LS0tCnRpdGxlOiAiUHJvamVjdCAxIC0gTGVvIExhbSIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQpJbmF1Z3VyYXRpb24gc3BlZWNoIGlzIGEgY2VyZW1vbnkgbWFya2luZyB0aGUgY29tbWVuY2VtZW50IG9mIGEgbmV3IHRlcm0gb2YgUHJlc2lkZW50IG9mIEFtZXJpY2EuIE9mdGVuLCBpbiB0aGlzIHNwZWVjaCwgUHJlc2lkZW50IGFkZHJlc3NlcyBoaXMgcG9saWNpZXMgYW5kIGZ1dHVyZSBwcmVzaWRlbnRpYWwgcGxhbnMuIEluIHRoaXMgc3R1ZHksIG91ciBnb2FsIGlzIHRvIGludmVzdGlnYXRlIHRoZSB1bmZvdW5kIHBhdHRlcm4gaW4gdGhlc2Ugc3BlZWNoZXMuIFdlIGZvY3VzIG9uIHRoZSBkaWZmZXJlbmNlcyBpbiBiZXR3ZWVuIFJlcHVibGljYW4gUHJlc2lkZW50cyBhbmQgRGVtb2NyYXRpYyBQcmVzaWRlbnRzIGFzIHdlbGwgYXMgUHJlc2lkZW50cyB3aG8gcmVjZWl2ZWQgZ3JhZHVhdGUgc2Nob29sIGVkdWNhdGlvbiBhbmQgUHJlc2lkZW50cyB3aG8gZGlkIG5vdC4gV2Ugd2FudCB0byBzZWUgaWYgZGlmZmVyZW50IGVkdWNhdGlvbmFsIGFuZCBwb2xpdGljYWwgYmFja2dyb3VuZHMgd2lsbCBoYXZlIGltcGFjdHMgb24gdGhlIHRvcGljLCB3b3JkIGxlbmd0aCwgc2VudGVuY2UgbGVuZ3RoLCBhbmQgZW1vdGlvbiBvZiB0aGVpciBpbmF1Z3VyYXRpb24gc3BlZWNoZXMuCgpCZWZvcmUgd2Ugc3RhcnQgYW5hbHl6aW5nIHRoZSBQcmVzaWRlbnQgaW5hdWd1cmF0aW9uIHNwZWVjaGVzLCB3ZSBoYXZlIHRvIGZpcnN0IGluc3RhbGwgYWxsIHBhY2thZ2VzIHdlIGFyZSBnb2luZyB0byB1c2UgaW4gdGhpcyByZXBvcnQuCmBgYHtyLG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CnBhY2thZ2VzLnVzZWQ9YygicnZlc3QiLCAidGliYmxlIiwgInFkYXAiLCAKICAgICAgICAgICAgICAgICJzZW50aW1lbnRyIiwgImdwbG90cyIsICJkcGx5ciIsCiAgICAgICAgICAgICAgICAidG0iLCAic3l1emhldCIsICJmYWN0b2V4dHJhIiwgCiAgICAgICAgICAgICAgICAiYmVlc3dhcm0iLCAic2NhbGVzIiwgIlJDb2xvckJyZXdlciIsCiAgICAgICAgICAgICAgICAiUkFOTiIsICJ0bSIsICJ0b3BpY21vZGVscyIsJ3JKYXZhJykKCiMgY2hlY2sgcGFja2FnZXMgdGhhdCBuZWVkIHRvIGJlIGluc3RhbGxlZC4KcGFja2FnZXMubmVlZGVkPXNldGRpZmYocGFja2FnZXMudXNlZCwgCiAgICAgICAgICAgICAgICAgICAgICAgIGludGVyc2VjdChpbnN0YWxsZWQucGFja2FnZXMoKVssMV0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFja2FnZXMudXNlZCkpCiMgaW5zdGFsbCBhZGRpdGlvbmFsIHBhY2thZ2VzCmlmKGxlbmd0aChwYWNrYWdlcy5uZWVkZWQpPjApewogIGluc3RhbGwucGFja2FnZXMocGFja2FnZXMubmVlZGVkLCBkZXBlbmRlbmNpZXMgPSBUUlVFKQp9CgojIGxvYWQgcGFja2FnZXMKbGlicmFyeShuZ3JhbSkKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KCJydmVzdCIpCmxpYnJhcnkoInRpYmJsZSIpCmxpYnJhcnkocWRhcCkKbGlicmFyeShySmF2YSkKbGlicmFyeSgic2VudGltZW50ciIpCmxpYnJhcnkoImdwbG90cyIpCmxpYnJhcnkoImRwbHlyIikKbGlicmFyeSgidG0iKQpsaWJyYXJ5KCJzeXV6aGV0IikKbGlicmFyeSgiZmFjdG9leHRyYSIpCmxpYnJhcnkoImJlZXN3YXJtIikKbGlicmFyeSgic2NhbGVzIikKbGlicmFyeSgiUkNvbG9yQnJld2VyIikKbGlicmFyeSgiUkFOTiIpCmxpYnJhcnkoInRvcGljbW9kZWxzIikKCmxpYnJhcnkod29yZGNsb3VkKQpsaWJyYXJ5KHRpZHl0ZXh0KQoKCnNvdXJjZSgifi9EZXNrdG9wL0NvbHVtYmlhL1NlbWVzdGVyIDIvQURTL1Byb2plY3QxL3drMi1UZXh0TWluaW5nL2xpYi9wbG90c3RhY2tlZC5SIikKc291cmNlKCJ+L0Rlc2t0b3AvQ29sdW1iaWEvU2VtZXN0ZXIgMi9BRFMvUHJvamVjdDEvd2syLVRleHRNaW5pbmcvbGliL3NwZWVjaEZ1bmNzLlIiKQpgYGAKCiMjIFN0ZXAgMSAtIEltcG9ydGluZyBzcGVlY2hlcwpUaGVuLCB3ZSBhcmUgZ29pbmcgdG8gaW1wb3J0IG91ciBpbmF1Z3VyYXRpb24gc3BlZWNoZXMgZnJvbSBodHRwOi8vd3d3LnByZXNpZGVuY3kudWNzYi5lZHUvaW5hdWd1cmFscy5waHAuIFdlIGFsc28gZm9ybWF0IHRoZSBkYXRlIGFuZCByZW1vdmUgaXJyZXZhbGVudCBpbmZvcm1hdGlvbiwgd2hpY2ggaXMgdGhlIGxhc3Qgcm93IG9mIG91ciBpbmF1ZyBmaWxlLgoKYGBge3IsIGluY2x1ZGU9RiwgZWNobz1GfQojIyMgSW5hdWd1YXJhbCBzcGVlY2hlcwptYWluLnBhZ2UgPC0gcmVhZF9odG1sKHggPSAiaHR0cDovL3d3dy5wcmVzaWRlbmN5LnVjc2IuZWR1L2luYXVndXJhbHMucGhwIikKaW5hdWc9Zi5zcGVlY2hsaW5rcyhtYWluLnBhZ2UpCmFzLkRhdGUoaW5hdWdbLDFdLCBmb3JtYXQ9IiVCICVlLCAlWSIpCmluYXVnPWluYXVnWy1ucm93KGluYXVnKSxdCmBgYAoKTm93LCB3ZSBpbXBvcnQgYSBjc3YgZmlsZSB0aGF0IGNvbnRhaW4gaW5mb3JtYXRpb24gb2YgdGhlIHByZXNpZGVudCwgaW5jbHVkaW5nIHByZXNpZGVudCdzIG5hbWUsIHRlcm0sIHBhcnR5LCBkYXRlLCBhbmQgbnVtYmVyIG9mIHdvcmRzIGNvbnRhaW5pbmcgaW4gdGhlIGluYXVndXJhdGlvbiBzcGVlY2guCmBgYHtyfQppbmF1Zy5saXN0PXJlYWQuY3N2KCJ+L0Rlc2t0b3AvQ29sdW1iaWEvU2VtZXN0ZXIgMi9BRFMvUHJvamVjdDEvd2syLVRleHRNaW5pbmcvZGF0YS9pbmF1Z2xpc3QuY3N2Iiwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQpgYGAKCkZvciB0aGUgZWFzZSBvZiBvdXIgZnVydGhlciBpbnZlc3RpZ2F0aW9uLCB3ZSBjb21iaW5lIGZpbGUgaW5hdWcgYW5kIGluYXVnLmxpc3QgdG9nZXRoZXIgaW50byBvbmUgc2luZ2xlIGZpbGUuCmBgYHtyfQppbmF1Zy5saXN0JHR5cGU9YyhyZXAoImluYXVnIiwgbnJvdyhpbmF1Zy5saXN0KSkpCnNwZWVjaC5saXN0PWNiaW5kKGluYXVnLmxpc3QsIGluYXVnKQpgYGAKCkFuZCB0aGVuLCB3ZSBhZGQgdGhlIGluYXVndXJhdGlvbiBzcGVlY2ggb2YgZWFjaCBwcmVzaWRlbnQgaW50byBhIG5ldyBjb2x1bW4gY2FsbGVkIGZ1bGx0ZXh0LgpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0Kc3BlZWNoLmxpc3QkZnVsbHRleHQ9TkEKZm9yKGkgaW4gc2VxKG5yb3coc3BlZWNoLmxpc3QpKSkgewogIHRleHQgPC0gcmVhZF9odG1sKHNwZWVjaC5saXN0JHVybHNbaV0pICU+JSAjIGxvYWQgdGhlIHBhZ2UKICAgIGh0bWxfbm9kZXMoIi5kaXNwbGF5dGV4dCIpICU+JSAjIGlzbG9hdGUgdGhlIHRleHQKICAgIGh0bWxfdGV4dCgpICMgZ2V0IHRoZSB0ZXh0CiAgc3BlZWNoLmxpc3QkZnVsbHRleHRbaV09dGV4dAogICMgQ3JlYXRlIHRoZSBmaWxlIG5hbWUKICBmaWxlbmFtZSA8LSBwYXN0ZTAoIn4vRGVza3RvcC9Db2x1bWJpYS9TZW1lc3RlciAyL0FEUy9Qcm9qZWN0MS93azItVGV4dE1pbmluZy9kYXRhL2Z1bGx0ZXh0LyIsIAogICAgICAgICAgICAgICAgICAgICBzcGVlY2gubGlzdCR0eXBlW2ldLAogICAgICAgICAgICAgICAgICAgICBzcGVlY2gubGlzdCRGaWxlW2ldLCAiLSIsIAogICAgICAgICAgICAgICAgICAgICBzcGVlY2gubGlzdCRUZXJtW2ldLCAiLnR4dCIpCiAgc2luayhmaWxlID0gZmlsZW5hbWUpICU+JSAjIG9wZW4gZmlsZSB0byB3cml0ZSAKICBjYXQodGV4dCkgICMgd3JpdGUgdGhlIGZpbGUKICBzaW5rKCkgIyBjbG9zZSB0aGUgZmlsZQp9CmBgYAoKIyMgU3RlcCAyIC0gRGF0YSBQcmVwcm9jZXNzaW5nCk5vdywgd2UgYmVnaW4gdG8gYW5hbHl6ZSB0aGUgc3BlZWNoIG9mIGVhY2ggcHJlc2lkZW50LiBXZSBmaXJzdCBzZXBhcmF0ZSBlYWNoIHNlbnRlbmNlIG9mIGFuIGluYXVndXJhdGlvbiBzcGVlY2ggYW5kIG9idGFpbiB0aGUgc2VudGltZW50IG9mIGVhY2ggc2VudGVuY2UgdXNpbmcgZ2V0X25yY19zZW50aW1lbnQoKSBjb21tYW5kLCB3aGljaCB3aWxsIHJldHVybiBzZW50aW1lbnQgb2YgYW5nZXIsIGFudGljaXBhdGlvbiwgZGlzZ3VzdCwgZmVhciwgam95LCBzYWRuZXNzLCBzdXJwcmlzZSwgdHJ1c3QsIG5lZ2F0aXZlLCBhbmQgcG9zaXRpdmUuIFdlIGNvbnNpZGVyICI/IiwgIi4iLCAiISIsICJ8IiwgYW5kICI7IiBhcyB0aGUgZW5kIG9mIGVhY2ggc2VudGVuY2UuIEFmdGVyIHdlIGZpbmlzaCB0aGUgYWJvdmUgc3RlcHMsIHdlIHJlbW92ZSBhbGwgdGhlIHJvd3Mgd2l0aCBOQSB2YWx1ZS4KYGBge3IsbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0Kc2VudGVuY2UubGlzdD1OVUxMCmZvcihpIGluIDE6bnJvdyhzcGVlY2gubGlzdCkpewogIHNlbnRlbmNlcz1zZW50X2RldGVjdChzcGVlY2gubGlzdCRmdWxsdGV4dFtpXSwKICAgICAgICAgICAgICAgICAgICAgICAgZW5kbWFya3MgPSBjKCI/IiwgIi4iLCAiISIsICJ8IiwiOyIpKSAKICBpZihsZW5ndGgoc2VudGVuY2VzKT4wKXsKICAgIGVtb3Rpb25zPWdldF9ucmNfc2VudGltZW50KHNlbnRlbmNlcykKICAgIHdvcmQuY291bnQ9d29yZF9jb3VudChzZW50ZW5jZXMpCiAgICBlbW90aW9ucz1kaWFnKDEvKHdvcmQuY291bnQrMC4wMSkpJSolYXMubWF0cml4KGVtb3Rpb25zKQogICAgc2VudGVuY2UubGlzdD1yYmluZChzZW50ZW5jZS5saXN0LCAKICAgICAgICAgICAgICAgICAgICAgICAgY2JpbmQoc3BlZWNoLmxpc3RbaSwtbmNvbChzcGVlY2gubGlzdCldLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZW50ZW5jZXM9YXMuY2hhcmFjdGVyKHNlbnRlbmNlcyksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3b3JkLmNvdW50LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbW90aW9ucywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VudC5pZD0xOmxlbmd0aChzZW50ZW5jZXMpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICkKICB9Cn0KCnNlbnRlbmNlLmxpc3Q9CiAgc2VudGVuY2UubGlzdCU+JQogIGZpbHRlcighaXMubmEod29yZC5jb3VudCkpCmBgYAoKIyMgU3RlcCAzIC0gRGF0YSBBbmFseXRpY3MKTGV0IHRoZSBmdW4gcGFydCBiZWdpbnMhIEluIHRoaXMgc3R1ZHksIHdlIHdpbGwgYW5hbHl6ZSB0aGUgZGlmZmVyZW5jZXMgaW4gYmV0d2VlbiB0aGUgaW5hdWd1cmF0aW9uIHNwZWVjaGVzIG9mIERlbW9jcmF0aWMgUHJlc2lkZW50cyBhbmQgUmVwdWJsaWNhbiBQcmVzaWRlbnRzIGFzIHdlbGwgYXMgdGhlIHByZXNpZGVudHMgd2hvIGF0dGVuZGVkIGdyYXVkYXRlIHNjaG9vbCBhbmQgdGhlIHByZXNpZGVudHMgd2hvIGRpZCBub3QgYXR0ZW5kIGdyYXVkYXRlIHNjaG9vbC4gV2UgdHJ5IHRvIGFuc3dlciB0aGUgcXVlc3Rpb24gb2Ygd2hhdCB3aWxsIGJlIHRoZSBkaWZmZXJlbmNlcyBpbiBlbW90aW9uLCB3b3JkIGxlbmd0aCwgc2VudGVuY2UgbGVuZ3RoLCBhbmQgdG9waWNzLgoKRmlyc3QsIGxldCB1cyBzZWxlY3QgdGhlIERlbW9jcmF0aWMgYW5kIFJlcHVibGljaWFuIFByZXNpZGVudHMuCmBgYHtyfQpkZW1vY3JhdGljID0gc3BlZWNoLmxpc3QkRmlsZVt3aGljaChzcGVlY2gubGlzdCRQYXJ0eT09J0RlbW9jcmF0aWMnKV0KZGVtb2NyYXRpYy5zcGVlY2guaW5kID0gd2hpY2goc3BlZWNoLmxpc3QkUGFydHk9PSdEZW1vY3JhdGljJykKZGVtb2NyYXRpYy5zZW50ZW5jZS5pbmQgPSB3aGljaChzZW50ZW5jZS5saXN0JFBhcnR5PT0nRGVtb2NyYXRpYycpCgpyZXB1YmxpY2FuID0gc3BlZWNoLmxpc3QkRmlsZVt3aGljaChzcGVlY2gubGlzdCRQYXJ0eT09J1JlcHVibGljYW4nKV0KcmVwdWJsaWNhbi5zcGVlY2guaW5kID0gd2hpY2goc3BlZWNoLmxpc3QkUGFydHk9PSdSZXB1YmxpY2FuJykKcmVwdWJsaWNhbi5zZW50ZW5jZS5pbmQgPSB3aGljaChzZW50ZW5jZS5saXN0JFBhcnR5PT0nUmVwdWJsaWNhbicpCmBgYAoKIyMgU3RlcCAzLjEgLSBOdW1iZXIgb2Ygd29yZHMgaW4gZWFjaCBzZW50ZW5jZQpUbyBvYnRhaW4gdGhlIG51bWJlciBvZiB3b3JkcyBpbiBlYWNoIHNlbnRlbmNlLCB3ZSB3cml0ZSBhIGZ1bmN0aW9uIGNhbGxlZCBzZW50ZW5jZS5sZW5ndGgsIHdoaWNoIHdpbGwgcmV0dXJuIGEgdmVjdG9yIHRoYXQgY29udGFpbnMgdGhlIGxlbmd0aCBvZiBlYWNoIHNlbnRlbmNlIG9mIGEgc3BlZWNoLgpgYGB7cn0Kc2VudGVuY2UubGVuZ3RoIDwtIGZ1bmN0aW9uKGluZGV4LCBkZil7CiAgc3BlZWNoLnZlYyA9IGRmJGZ1bGx0ZXh0CiAgYSA9IHN0cnNwbGl0KHNwZWVjaC52ZWNbaW5kZXhdLCAnWz8hOy58XScpCiAgcmVzLnZlYyA9IGMoKQogIGZvcihqIGluIDE6bGVuZ3RoKGFbWzFdXSkpewogICAgcmVzLnZlYyA9IGNiaW5kKHJlcy52ZWMsIHdvcmRjb3VudChhW1sxXV1bW2pdXSkpCiAgfQogIHJldHVybihyZXMudmVjKQp9CmBgYAoKVGhlbiwgd2UgYXBwbHkgdGhlIHNlbnRlbmNlLmxlbmd0aCBmdW5jdGlvbiBpbnRvIGJvdGggRGVtb2NyYXRpYyBhbmQgUmVwdWJsaWNhbiBpbmF1Z3VyYXRpb24gc3BlZWNoZXMuIFNpbmNlIHRoZSBmaXJzdCBkZW1vY3JhdGljIHByZXNpZGVudCBpcyBBbmRyZXcgSmFja3NvbiBhcyBoaXMgcHJlZGVjZXNzb3JzIGFyZSBhbGwgZGVtb2NyYXRpYy1yZXB1YmxpY2FuIHBhcnR5IG9yIEZlZHJhbGlzdCwgd2hpY2ggYm90aCBwYXJ0aWVzIGRvIG5vdCBleGlzdCBhbnltb3JlLCB3ZSB3aWxsIG9ubHkgY29uc2lkZXIgdGhlIHByZXNpZGVudHMgYWZ0ZXIgUHJlc2lkZW50IEphY2tzb24uIFdlIGRvIG5vdCBjb25zaWRlciBXaGlnIGluIHRoaXMgc3R1ZHkgYXMgaXQgYWxzbyBkb2Vzbid0IGV4aXN0IHRvZGF5LgpgYGB7cn0KbWVhbi5sZW5ndGguZGVtb2NyYXRpYyA9IDAKZm9yKGkgaW4gZGVtb2NyYXRpYy5zcGVlY2guaW5kKXsKICBtZWFuLmxlbmd0aC5kZW1vY3JhdGljID0gbWVhbi5sZW5ndGguZGVtb2NyYXRpYyArIG1lYW4oc2VudGVuY2UubGVuZ3RoKGksIHNwZWVjaC5saXN0KSkKfQptZWFuLmxlbmd0aC5kZW1vY3JhdGljID0gbWVhbi5sZW5ndGguZGVtb2NyYXRpYy9sZW5ndGgoZGVtb2NyYXRpYy5zcGVlY2guaW5kKQoKbWVhbi5sZW5ndGgucmVwdWJsaWNhbiA9IDAKZm9yKGkgaW4gcmVwdWJsaWNhbi5zcGVlY2guaW5kKXsKICBtZWFuLmxlbmd0aC5yZXB1YmxpY2FuID0gbWVhbi5sZW5ndGgucmVwdWJsaWNhbiArIG1lYW4oc2VudGVuY2UubGVuZ3RoKGksIHNwZWVjaC5saXN0KSkKfQptZWFuLmxlbmd0aC5yZXB1YmxpY2FuID0gbWVhbi5sZW5ndGgucmVwdWJsaWNhbi9sZW5ndGgocmVwdWJsaWNhbi5zcGVlY2guaW5kKQoKY2F0KCdEZW1vY3JhdGljIGF2ZXJhZ2UgbnVtYmVyIG9mIHdvcmRzIGluIGVhY2ggc2VudGVuY2UnLChtZWFuLmxlbmd0aC5kZW1vY3JhdGljKSwnXG4nKQpjYXQoJ1JlcHVibGljYW4gYXZlcmFnZSBudW1iZXIgb2Ygd29yZHMgaW4gZWFjaCBzZW50ZW5jZScsKG1lYW4ubGVuZ3RoLnJlcHVibGljYW4pKQoKZGYubGVuZ3RoLnJlcHZzZGVtID0gY2JpbmQobWVhbi5sZW5ndGgucmVwdWJsaWNhbixtZWFuLmxlbmd0aC5kZW1vY3JhdGljKQpiYXJwbG90KGRmLmxlbmd0aC5yZXB2c2RlbSkKYGBgCldoaWxlIHJlcHVibGljYW4gYXZlcmFnZSBudW1iZXIgb2Ygd29yZHMgaXMgbG93ZXIgdGhhbiBkZW1vY3JhdGljKGRlbW9jcmF0aWMgPSAyMy43OTk1MiB2cyBSZXB1YmxpY2FuID0gMjIuMzA3NjIpLCB0aGVyZSBpc24ndCBhIG1ham9yIGRpZmZlcmVuY2UgaW4gbnVtYmVyIG9mIHdvcmRzIGluIGVhY2ggc2VudGVuY2UgYmV0d2VlbiBwcmVzaWRlbnRzIG9mIGJvdGggcGFydGllcy4gSGVuY2UsIHdlIGJlZ2luIHRvIHN1c3BlY3Qgd291bGQgZ29pbmcgdG8gZ3JhZHVhdGUgc2Nob29sIGhhcyBhIHBvc2l0aXZlIGltcGFjdCBvZiB0aGUgYXZlcmFnZSBudW1iZXIgb2Ygd29yZHMgaW4gZWFjaCBzZW50ZW5jZS4gT3VyIGh5cG90aGVzaXMgaXMgZ29pbmcgdG8gZ3JhZHVhdGUgc2Nob29sIG1heSBpbmNyZWFzZSB0aGUgcHJvYmFiaWxpdHkgb2YgdGhlIHVzZSBvZiBsb25nZXIgc2VudGVuY2VzLgoKVXNpbmcgdGhlIGluZm9ybWF0aW9uIGZyb20gV2lraXBlZGlhLCB3ZSBvYnRhaW4gdGhlIGxpc3Qgb2YgcHJlc2lkZW50cyBpbiBib3RoIHBhcnRpZXMgd2hvIGRpZCBub3QgYXR0ZW5kIGdyYWR1YXRlIHNjaG9vbC4gQWdhaW4sIHdlIG9ubHkgY29uc2lkZXIgcHJlc2lkZW50cyBhZnRlciBBbmRyZXcgSmFja3Nvbi4gKExpc3Qgb2YgUHJlc2lkZW50czogaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvTGlzdF9vZl9QcmVzaWRlbnRzX29mX3RoZV9Vbml0ZWRfU3RhdGVzKSAoRWR1Y2F0aW9uIG9mIFByZXNpZGVudDogaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvTGlzdF9vZl9QcmVzaWRlbnRzX29mX3RoZV9Vbml0ZWRfU3RhdGVzX2J5X2VkdWNhdGlvbikKYGBge3J9CiMgcmVwdWJsaWNhbiBwcmVzaWRlbnQgd2hvIGRpZCBub3QgYXR0ZW5kIGdyYWR1YXRlIHNjaG9vbApuby5ncmFkLnJlcCA9IGMoJ0FicmFoYW1MaW5jb2xuJywnVWx5c3Nlc1NHcmFudCcsJ0phbWVzR2FyZmllbGQnLCdCZW5qYW1pbkhhcnJpc29uJywgJ1dpbGxpYW1NY0tpbmxleScsJ1RoZW9kb3JlUm9vc2V2ZWx0JywnV2FycmVuR0hhcmRpbmcnLCdDYWx2aW5Db29saWRnZScsICdIZXJiZXJ0SG9vdmVyJywnUm9uYWxkUmVhZ2FuJywnR2VvcmdlQnVzaCcsJ0RvbmFsZEpUcnVtcCcpCgpuby5ncmFkLnJlcC5zcGVlY2guaW5kID0gYygpCmZvcihpIGluIG5vLmdyYWQucmVwKXsKICBuby5ncmFkLnJlcC5zcGVlY2guaW5kID0gYyhuby5ncmFkLnJlcC5zcGVlY2guaW5kLCB3aGljaChpID09IHNwZWVjaC5saXN0JEZpbGUpKQp9Cgpuby5ncmFkLnJlcC5zZW50ZW5jZS5pbmQgPSBjKCkKZm9yKGkgaW4gbm8uZ3JhZC5yZXApewogIG5vLmdyYWQucmVwLnNlbnRlbmNlLmluZCA9IGMobm8uZ3JhZC5yZXAuc2VudGVuY2UuaW5kLCB3aGljaChpID09IHNlbnRlbmNlLmxpc3QkRmlsZSkpCn0KCiMgZGVtb2NyYXRpYyBwcmVzaWRlbnQgd2hvIGRpZCBub3QgYXR0ZW5kIGdyYWRhdXRlIHNjaG9vbApuby5ncmFkLmRlbSA9IGMoJ0FuZHJld0phY2tzb24nLCdNYXJ0aW52YW5CdXJlbicsJ0phbWVzS1BvbGsnLCdKYW1lc0J1Y2hhbmFuJywKICAgICAgICAgICAgICAgICdHcm92ZXJDbGV2ZWxhbmQtSScsJ0dyb3ZlckNsZXZlbGFuZC1JSScsJ0hhcnJ5U1RydW1hbicsCiAgICAgICAgICAgICAgICAnSm9obkZLZW5uZWR5JykKCm5vLmdyYWQuZGVtLnNwZWVjaC5pbmQgPSBjKCkKZm9yKGkgaW4gbm8uZ3JhZC5kZW0pewogIG5vLmdyYWQuZGVtLnNwZWVjaC5pbmQgPSBjKG5vLmdyYWQuZGVtLnNwZWVjaC5pbmQsIHdoaWNoKGkgPT0gc3BlZWNoLmxpc3QkRmlsZSkpCn0KCm5vLmdyYWQuZGVtLnNlbnRlbmNlLmluZCA9IGMoKQpmb3IoaSBpbiBuby5ncmFkLmRlbSl7CiAgbm8uZ3JhZC5kZW0uc2VudGVuY2UuaW5kID0gYyhuby5ncmFkLmRlbS5zZW50ZW5jZS5pbmQsIHdoaWNoKGkgPT0gc2VudGVuY2UubGlzdCRGaWxlKSkKfQpjYXQoJ091dCBvZiB0b3RhbCcsIGxlbmd0aChyZXB1YmxpY2FuKSwncmVwdWJsaWNhbiBwcmVzaWRlbnRzLCcsJ251bWJlciBvZiByZXB1YmxpY2FuIHByZXNpZGVudHMgd2hvIGRpZCBub3QgYXR0ZW5kIGdyYWR1YXRlIHNjaG9vbDonLCBsZW5ndGgobm8uZ3JhZC5yZXApLCdcbicpCmNhdCgnT3V0IG9mIHRvdGFsJywgbGVuZ3RoKGRlbW9jcmF0aWMpLCdkZW1vY3JhdGljIHByZXNpZGVudHMsJywnbnVtYmVyIG9mIGRlbW9jcmF0aWMgcHJlc2lkZW50cyB3aG8gZGlkIG5vdCBhdHRlbmQgZ3JhZHVhdGUgc2Nob29sOicsIGxlbmd0aChuby5ncmFkLmRlbSksJ1xuJykKYGBgCkZyb20gYWJvdmUsIHdlIG5vdGljZSB0aGVyZSBhcmUgbW9yZSByZXB1YmxpY2FuIHByZXNpZGVudHMgd2hvIGRpZCBub3QgYXR0ZW5kIGdyYWR1YXRlIHNjaG9vbC4gVGhpcyBtYXkgZXhwbGFpbiB3aHkgcmVwdWJsaWNhbiBoYXMgYW4gb3ZlcmFsbCBsb3dlciBhdmVyYWdlIG51bWJlciBvZiB3b3JkcyBpbiBlYWNoIHNlbnRlbmNlLCB3aGljaCBtYXkgc3VwcG9ydCBvdXIgaHlwb3RoZXNpcyBvZiB0aGVyZSBleGlzdHMgYSBwb3NpdGl2ZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIGdvaW5nIHRvIGdyYWR1YXRlIHNjaG9vbCBhbmQgdGhlIHVzZSBvZiBsb25nZXIgc2VudGVuY2UuCgpUbyBnZXQgYSBtb3JlIGFjY3VyYXRlIGV4cGxhbmF0aW9uLCBsZXQncyBsb29rIGF0IHRoZSBudW1iZXIgb2Ygc3R1ZGVudHMgd2hvIGF0dGVuZCBncmFkdWF0ZSBzY2hvb2wgaW4gZGlmZmVyZW50IHBlcmlvZCBvZiB0aW1lLiBXZSBmb3VuZCBhIGRhdGFzZXQgZnJvbSBXaWtpcGVkaWEsIHdoaWNoIHByb3ZpZGVzIHRoZSBudW1iZXIgb2Ygc3R1ZGVudHMgd2hvIGF0dGVuZGVkIHVuZGVyZ3JhZHVhdGUgYW5kIGdyYWR1YXRlIHNjaG9vbCBzaW5jZSAxODkwLiAoaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvSGlzdG9yeV9vZl9oaWdoZXJfZWR1Y2F0aW9uX2luX3RoZV9Vbml0ZWRfU3RhdGVzKQpgYGB7cn0KeWVhci4gPC0gYygxODcwLDE4OTAsMTkxMCwxOTMwLDE5NTAsMTk3MCwxOTkwLCAyMDA5KQpCQS4gPC0gYyg5NDAwLDE1NTAwLDM3MjAwLDEyMjUwMCw0MzIwMDAsODI3MDAwLDEwNTIwMDAsMTYwMDAwMCkKTUEuIDwtIGMoTkEsMTAwMCwyMTAwLDE1MDAwLDU4MjAwLDIwODAwMCwzMjUwMDAsNjU3MDAwKQpkZi5kZWdyZWUgPC0gZGF0YS5mcmFtZSh5ZWFyLiwgQkEuLCBNQS4pCgpnZ3Bsb3QoZGYuZGVncmVlKSsKICBnZW9tX2xpbmUoYWVzKHg9eWVhci4sIHk9QkEuLCBjb2wgPSAnQmFjaGVsb3IgZGVncmVlJykpKwogIGdlb21fbGluZShhZXMoeD15ZWFyLiwgeT1NQS4sIGNvbCA9ICdNYXN0ZXIgZGVncmVlJykpKwogIHlsYWIoJ251bWJlciBvZiBzdHVkZW50JykKYGBgCkFzIHdlIGNhbiBzZWUgZnJvbSB0aGUgZ3JhcGgsIHRoZXJlIHdlcmUgZmV3ZXIgdGhhbiAxMDAwIHN0dWRlbnRzIGF0dGVuZGluZyBncmFkdWF0ZSBzY2hvb2wgYmVmb3JlIDE4OTAuIFRoZXJlZm9yZSwgd2UgaHlwb3RoZXNpemUgdGhhdCBpdCB3YXMgbXVjaCBoYXJkZXIgdG8gYXR0ZW5kIGdyYXVkYXRlIHNjaG9vbCBiZWZvcmUgMTg5MCwgd2hpY2ggbWVhbnMgdGhlIHByZXNpZGVudHMgd2hvIGF0dGVuZGVkIGdyYXVkYXRlIHNjaG9vbCBiZWZvcmUgMTg5MCBtaWdodCBoYXZlIGEgYmV0dGVyIGVkdWNhdGlvbmFsIGJhY2tncm91bmQgYW5kIGFiaWxpdHkuIFRoZSBoeXBvdGhlc2lzIGhlcmUgaXMgYXR0ZW5kaW5nIGdyYWR1YXRlIHNjaG9vbCBiZWZvcmUgMTg5MCBoYXMgYSBzdHJvbmdlciBpbXBhY3Qgb24gdGhlIHRlbmRlbmN5IG9mIHVzaW5nIGxvbmdlciBzZW50ZW5jZXMgdGhhbiBhdHRlbmRpbmcgZ3JhZHVhdGUgc2Nob29sIGFmdGVyIDE4OTAuCgpgYGB7cixtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBpbmNsdWRlPUYsIGVjaG89Rn0KIyBTaW5jZSBtb3N0IG9mIHRoZSBncmF1ZGF0ZSBzY2hvb2xzIGJ1aWx0IGFmdGVyIDE4OTAsIGxldHMgZXhhbWluZSBvdXIgZGF0YSBmaWx0ZXJpbmcgb3V0IGRhdGEgYmVmb3JlIDE4OTAKc3BlZWNoLmxpc3QkRGF0ZVsyN10gIyBleGFtaW5lIGRhdGEgYWZ0ZXIgMTg5Mwpuby5ncmFkID0gdW5pb24obm8uZ3JhZC5kZW0sbm8uZ3JhZC5yZXApCm5vLmdyYWQuaW5kID0gdW5pb24obm8uZ3JhZC5kZW0uc3BlZWNoLmluZCwgbm8uZ3JhZC5yZXAuc3BlZWNoLmluZCkKCm5vLmdyYWQuYTE4OTAuaW5kID0gbm8uZ3JhZC5pbmRbbm8uZ3JhZC5pbmQgPj0gMjddCm5vLmdyYWQuYTE4OTAgPSBzcGVlY2gubGlzdCRGaWxlW25vLmdyYWQuYTE4OTAuaW5kXQpncmFkLmExODkwLmluZCA9ICgxOjU4KVstbm8uZ3JhZC5hMTg5MC5pbmRdWzI2OjQ1XQoKbm8uZ3JhZC5iMTg5MC5pbmQgPSBuby5ncmFkLmluZFtuby5ncmFkLmluZCA8IDI3XQpuby5ncmFkLmIxODkwID0gc3BlZWNoLmxpc3QkRmlsZVtuby5ncmFkLmIxODkwLmluZF0KZ3JhZC5iMTg5MC5pbmQgPSAoMTo1OClbLW5vLmdyYWQuYjE4OTAuaW5kXVsxMToxNF0KYGBgCmBgYHtyfQptZWFuLnNlbnRlbmNlLmxlbmd0aC5uby5ncmFkLmExODkwID0gMApmb3IoaSBpbiBuby5ncmFkLmExODkwLmluZCl7CiAgbWVhbi5zZW50ZW5jZS5sZW5ndGgubm8uZ3JhZC5hMTg5MCA9IG1lYW4uc2VudGVuY2UubGVuZ3RoLm5vLmdyYWQuYTE4OTAgKyBtZWFuKHNlbnRlbmNlLmxlbmd0aChpLCBzcGVlY2gubGlzdCkpCn0KbWVhbi5zZW50ZW5jZS5sZW5ndGgubm8uZ3JhZC5hMTg5MCA9IG1lYW4uc2VudGVuY2UubGVuZ3RoLm5vLmdyYWQuYTE4OTAvbGVuZ3RoKG5vLmdyYWQuYTE4OTAuaW5kKSAgCiAgCm1lYW4uc2VudGVuY2UubGVuZ3RoLmdyYWQuYTE4OTAgPSAwCmZvcihpIGluIGdyYWQuYTE4OTAuaW5kKXsKICBtZWFuLnNlbnRlbmNlLmxlbmd0aC5ncmFkLmExODkwID0gbWVhbi5zZW50ZW5jZS5sZW5ndGguZ3JhZC5hMTg5MCArIG1lYW4oc2VudGVuY2UubGVuZ3RoKGksIHNwZWVjaC5saXN0KSkKfQptZWFuLnNlbnRlbmNlLmxlbmd0aC5ncmFkLmExODkwID0gbWVhbi5zZW50ZW5jZS5sZW5ndGguZ3JhZC5hMTg5MC9sZW5ndGgoZ3JhZC5hMTg5MC5pbmQpICAKCgptZWFuLnNlbnRlbmNlLmxlbmd0aC5uby5ncmFkLmIxODkwID0gMApmb3IoaSBpbiBuby5ncmFkLmIxODkwLmluZCl7CiAgbWVhbi5zZW50ZW5jZS5sZW5ndGgubm8uZ3JhZC5iMTg5MCA9IG1lYW4uc2VudGVuY2UubGVuZ3RoLm5vLmdyYWQuYjE4OTAgKyBtZWFuKHNlbnRlbmNlLmxlbmd0aChpLCBzcGVlY2gubGlzdCkpCn0KbWVhbi5zZW50ZW5jZS5sZW5ndGgubm8uZ3JhZC5iMTg5MCA9IG1lYW4uc2VudGVuY2UubGVuZ3RoLm5vLmdyYWQuYjE4OTAvbGVuZ3RoKG5vLmdyYWQuYTE4OTAuaW5kKSAgCiAgCm1lYW4uc2VudGVuY2UubGVuZ3RoLmdyYWQuYjE4OTAgPSAwCmZvcihpIGluIGdyYWQuYjE4OTAuaW5kKXsKICBtZWFuLnNlbnRlbmNlLmxlbmd0aC5ncmFkLmIxODkwID0gbWVhbi5zZW50ZW5jZS5sZW5ndGguZ3JhZC5iMTg5MCArIG1lYW4oc2VudGVuY2UubGVuZ3RoKGksIHNwZWVjaC5saXN0KSkKfQptZWFuLnNlbnRlbmNlLmxlbmd0aC5ncmFkLmIxODkwID0gbWVhbi5zZW50ZW5jZS5sZW5ndGguZ3JhZC5iMTg5MC9sZW5ndGgoZ3JhZC5iMTg5MC5pbmQpCgp4LmIxODkwID0gYyhtZWFuLnNlbnRlbmNlLmxlbmd0aC5ncmFkLmIxODkwLG1lYW4uc2VudGVuY2UubGVuZ3RoLm5vLmdyYWQuYjE4OTApCnguYTE4OTAgPSBjKG1lYW4uc2VudGVuY2UubGVuZ3RoLmdyYWQuYTE4OTAsbWVhbi5zZW50ZW5jZS5sZW5ndGgubm8uZ3JhZC5hMTg5MCkKZGYuYWIxODkwID0gKGNiaW5kKHguYjE4OTAseC5hMTg5MCkpCnJvd25hbWVzKGRmLmFiMTg5MCkgPSBjKCdncmFkdWF0ZSBzY2hvb2wnLCAnbm8gZ3JhZHVhdGUgc2Nob29sJykKYmFycGxvdChkZi5hYjE4OTAsIGJlc2lkZT1ULCBjb2w9MToyLCB5bGFiPSdhdmVyYWdlIHNlbnRlbmNlIGxlbmd0aCcpCmxlZ2VuZCgndG9wcmlnaHQnLGxlZ2VuZD1jKCdncmFkdWF0ZScsICdubyBncmFkdWF0ZScpLGNvbD0xOjIsIGZpbGwgPSAxOjIpCgpgYGAKVGhlIGxlZnQgc2hvd3MgdGhlIGF2ZXJhZ2Ugc2VudGVuY2UgbGVuZ3RoIGJlZm9yZSAxODkwIHdoaWxlIHRoZSByaWdodCBzaG93cyB0aGUgYXZlcmFnZSBzZW50ZW5jZSBsZW5ndGggYWZ0ZXIgMTg5MC4gVGhlIHJlc3VsdCBhZ3JlZXMgd2l0aCBvdXIgaHlwb3RoZXNpcyBvZiBnb2luZyB0byBncmFkdWF0ZSBzY2hvb2wgYmVmb3JlIDE4OTAgbWF5IGhhdmUgYSBiaWdnZXIgaW1wYWN0IG9uIHRoZSB0ZW5kZW5jeSBvZiB0aGUgdXNlIG9mIGxvbmdlciBzZW50ZW5jZXMuIFRoaXMgcmVzdWx0IGFsc28gc2hvd3MgZ29pbmcgdG8gZ3JhZHVhdGUgc2Nob29sIGFmdGVyIDE4OTAgZG9lc24ndCBoYXZlIGEgc2lnbmlmaWNhbnQgaW1wYWN0IG9uIHRoZSBhdmVyYWdlIG51bWJlciBvZiB3b3JkcyBpbiBlYWNoIHNlbnRlbmNlLCB3aGljaCBtYXkgaW5kaWNhdGUgdGhlIGRpZmZpY3VsdHkgb2YgZ29pbmcgdG8gZ3JhZHVhdGUgZGVjcmVhc2VkIGFzIHRoZXJlIGFyZSBzaWduaWZpY2FudCBoaWdoZXIgYW1vdW50IG9mIGdyYWR1YXRlIHN0dWRlbnQgYWZ0ZXIgMTg5MC4gVGhpcyBpbmRpY2F0ZXMgdGhlIHF1YWxpdHkgb2YgZ3JhZHVhdGUgc3R1ZGVudCBtaWdodCBhcyB3ZWxsIGRlY3JlYXNlIGNhdXNpbmcgbGVzcyBpbXBhY3Qgb24gdGhlIGFiaWxpdHkgb2YgdXNpbmcgbG9uZ2VyIHNlbnRlbmNlcy4gQnV0IHdlIHdpbGwgbm90IGZ1cnRoZXIgaW52ZXN0aWdhdGUgdGhlIHF1YWxpdHkgb2YgZ3JhZHVhdGUgc2Nob29sIGVkdWNhdGlvbiBhcyB3ZSB3b3VsZCBmb2N1cyBtb3JlIG9uIHByZXNpZGVudCBpbmF1Z3VyYXRpb24gc3BlZWNoIGluIHRoaXMgc3R1ZHkuCgpOb3csIHdlIHdpbGwgdGFrZSBhIGxvb2sgb2YgdGhlIG51bWJlciBvZiB3b3JkcyBpbiBlYWNoIHNlbnRlbmNlIGZvciBlYWNoIHByZXNpZGVudCB1c2luZyBiZWVzd2FybSgpLgpgYGB7cn0Kc2VudGVuY2UubGlzdC5zZWw9c2VudGVuY2UubGlzdCU+JWZpbHRlcih0eXBlPT0iaW5hdWciLCBGaWxlJWluJWMocmVwdWJsaWNhbiwgZGVtb2NyYXRpYyksIFRlcm09PTEpCnNlbnRlbmNlLmxpc3Quc2VsJEZpbGU9ZmFjdG9yKHNlbnRlbmNlLmxpc3Quc2VsJEZpbGUpCgpzZW50ZW5jZS5saXN0LnNlbCRGaWxlT3JkZXJlZD1yZW9yZGVyKHNlbnRlbmNlLmxpc3Quc2VsJEZpbGUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VudGVuY2UubGlzdC5zZWwkd29yZC5jb3VudCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZWFuLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9yZGVyPVQpCnBhcihtYXI9Yyg0LCAxMSwgMiwgMikpCgpiZWVzd2FybSh3b3JkLmNvdW50fkZpbGVPcmRlcmVkLCAKICAgICAgICAgZGF0YT1zZW50ZW5jZS5saXN0LnNlbCwKICAgICAgICAgaG9yaXpvbnRhbCA9IFRSVUUsCiAgICAgICAgIHBjaD0xNiwgY29sPWFscGhhKGJyZXdlci5wYWwoOSwgIlNldDEiKSwgMC42KSwgCiAgICAgICAgIGNleD0wLjU1LCBjZXguYXhpcz0wLjgsIGNleC5sYWI9MC44LAogICAgICAgICBzcGFjaW5nPTUvbmxldmVscyhzZW50ZW5jZS5saXN0LnNlbCRGaWxlT3JkZXJlZCksCiAgICAgICAgIGxhcz0yLCB5bGFiPSIiLCB4bGFiPSJOdW1iZXIgb2Ygd29yZHMgaW4gYSBzZW50ZW5jZS4iLAogICAgICAgICBtYWluPSJJbmF1Z3VyYWwgU3BlZWNoZXMiKQpgYGAKVGhpcyBncmFwaCBhYm92ZSBmdXJ0aGVyIGFncmVlcyB3aXRoIG91ciBoeXBvdGhlc2lzIG9mIHByZXNpZGVudHMgd2hvIGF0dGVuZGVkIGdyYWR1YXRlIHNjaG9vbCBiZWZvcmUgMTg5MCB0ZW5kIHRvIHVzZSBsb25nZXIgc2VudGVuY2VzIGFzIG1vc3Qgb2YgdGhlIHByZXNpZGVudHMgd2hvIHVzZSBsb25nZXIgc2VudGVuY2UgYXJlIHRoZSBwcmVzaWRlbnRzIHdobyBhdHRlbmQgZ3JhZHVhdGUgc2Nob29sIGJlZm9yZSAxODkwIChwcmVzaWRlbnRzIG5lYXIgdGhlIHRvcCBvZiB0aGUgbGlzdCkuIFRoZSBncmFwaCBhYm92ZXMgYWxzbyBzaG93cyB1cyB0aGUgbnVtYmVyIG9mIHdvcmRzIGluIGVhY2ggc2VudGVuY2Ugb2YgZWFjaCBwcmVzaWRlbnQuCgpOb3csIGxldCdzIHRha2UgYSBsb29rIG9mIHRoZSBpbmF1Z3VyYXRpb24gc3BlZWNoIGNvbnRlbnQgb2YgdGhlIHByZXNpZGVudCB3aG8gdXNlZCB0aGUgc2hvcnRlc3Qgc2VudGVuY2VzLCBHZW9yZ2UgQnVzaC4KYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmNvcnB1czEgPSBWQ29ycHVzKFZlY3RvclNvdXJjZShzcGVlY2gubGlzdCRmdWxsdGV4dFtzcGVlY2gubGlzdCRGaWxlPT0nR2VvcmdlQnVzaCddKSkKY29ycHVzMTwtdG1fbWFwKGNvcnB1czEsIHN0cmlwV2hpdGVzcGFjZSkKY29ycHVzMTwtdG1fbWFwKGNvcnB1czEsIGNvbnRlbnRfdHJhbnNmb3JtZXIodG9sb3dlcikpCmNvcnB1czE8LXRtX21hcChjb3JwdXMxLCByZW1vdmVXb3Jkcywgc3RvcHdvcmRzKCJlbmdsaXNoIikpCmNvcnB1czE8LXRtX21hcChjb3JwdXMxLCByZW1vdmVXb3JkcywgY2hhcmFjdGVyKDApKQpjb3JwdXMxPC10bV9tYXAoY29ycHVzMSwgcmVtb3ZlUHVuY3R1YXRpb24pCnRkbS5hbGw8LVRlcm1Eb2N1bWVudE1hdHJpeChjb3JwdXMxKQp0ZG0udGlkeT10aWR5KHRkbS5hbGwpCnRkbS5vdmVyYWxsPXN1bW1hcmlzZShncm91cF9ieSh0ZG0udGlkeSwgdGVybSksIHN1bShjb3VudCkpCgp3b3JkY2xvdWQodGRtLm92ZXJhbGwkdGVybSwgdGRtLm92ZXJhbGwkYHN1bShjb3VudClgLAogICAgICAgICAgc2NhbGU9Yyg1LDAuNSksCiAgICAgICAgICBtYXgud29yZHM9MTAwLAogICAgICAgICAgbWluLmZyZXE9MSwKICAgICAgICAgIHJhbmRvbS5vcmRlcj1GQUxTRSwKICAgICAgICAgIHJvdC5wZXI9MC4zLAogICAgICAgICAgdXNlLnIubGF5b3V0PVQsCiAgICAgICAgICByYW5kb20uY29sb3I9RkFMU0UsCiAgICAgICAgICBjb2xvcnM9YnJld2VyLnBhbCg5LCJCbHVlcyIpKQpgYGAKQXMgd2UgY2FuIHNlZSBmcm9tIHRoZSB3b3JkY2xvdWQgYWJvdmUsIFByZXNpZGVudCBCdXNoIG1lbnRpb25lZCB3b3JkcyBsaWtlIG5hdGlvbiwgZnJlZWRvbSwgZnJpZW5kcywgZXRjLCB3aGNpaCBhcmUgdG9waWNzIHJlbGF0ZWQgdG8gYW1lcmljYW4gZHJlYW0gYW5kIGZhaXRoLiBQcmVzaWRlbnQgQnVzaCB1c2VkICd3aWxsJyBhIGxvdCBpbiBoaXMgc3BlZWNoLCB3aGljaCBpcyB2ZXJ5IHJlYXNvbmFibGUgYXMgcHJlc2lkZW50cyB0ZW5kIHRvIGV4cHJlc3MgdGhlaXIgZnV0dXJlIHBsYW4gYW5kIHBvbGljeSBpbiB0aGVpciBpbmF1Z3VyYXRpb24gc3BlZWNoLgoKTmV4dCwgbGV0J3MgbG9vayBhdCBEb25hbGQgVHJ1bXAncyB3b3JkY2xvdWQsIHdobyB1c2UgdGhlIHNlY29uZCBzaG9ydGVzdCBzZW50ZW5jZXMuCmBgYHtyfQpjb3JwdXMxID0gVkNvcnB1cyhWZWN0b3JTb3VyY2Uoc3BlZWNoLmxpc3QkZnVsbHRleHRbc3BlZWNoLmxpc3QkRmlsZT09J0RvbmFsZEpUcnVtcCddKSkKY29ycHVzMTwtdG1fbWFwKGNvcnB1czEsIHN0cmlwV2hpdGVzcGFjZSkKY29ycHVzMTwtdG1fbWFwKGNvcnB1czEsIGNvbnRlbnRfdHJhbnNmb3JtZXIodG9sb3dlcikpCmNvcnB1czE8LXRtX21hcChjb3JwdXMxLCByZW1vdmVXb3Jkcywgc3RvcHdvcmRzKCJlbmdsaXNoIikpCmNvcnB1czE8LXRtX21hcChjb3JwdXMxLCByZW1vdmVXb3JkcywgY2hhcmFjdGVyKDApKQpjb3JwdXMxPC10bV9tYXAoY29ycHVzMSwgcmVtb3ZlUHVuY3R1YXRpb24pCnRkbS5hbGw8LVRlcm1Eb2N1bWVudE1hdHJpeChjb3JwdXMxKQp0ZG0udGlkeT10aWR5KHRkbS5hbGwpCnRkbS5vdmVyYWxsPXN1bW1hcmlzZShncm91cF9ieSh0ZG0udGlkeSwgdGVybSksIHN1bShjb3VudCkpCgp3b3JkY2xvdWQodGRtLm92ZXJhbGwkdGVybSwgdGRtLm92ZXJhbGwkYHN1bShjb3VudClgLAogICAgICAgICAgc2NhbGU9Yyg1LDAuNSksCiAgICAgICAgICBtYXgud29yZHM9MTAwLAogICAgICAgICAgbWluLmZyZXE9MSwKICAgICAgICAgIHJhbmRvbS5vcmRlcj1GQUxTRSwKICAgICAgICAgIHJvdC5wZXI9MC4zLAogICAgICAgICAgdXNlLnIubGF5b3V0PVQsCiAgICAgICAgICByYW5kb20uY29sb3I9RkFMU0UsCiAgICAgICAgICBjb2xvcnM9YnJld2VyLnBhbCg5LCJCbHVlcyIpKQpgYGAKUHJlc2lkZW50IFRydW1wIHNlZW1zIHRvIGZvY3VzIG9uIHRvcGljIGFib3V0ICdBbWVyaWNhbicgYW5kICdEcmVhbScuIEJ5IGNvbXBhcmluZyB0aGUgd29yZGNsb3VkIG9mIGJvdGggcHJlc2lkZW50cywgUHJlc2lkZW50IEJ1c2gncyBpbmF1Z3VyYXRpb24gc2VlbXMgdG8gY292ZXIgbW9yZSBjb21wcmVoZW5zaXZlIHdvcmRzIGFzIFByZXNpZGVudCBUcnVtcCBzZWVtcyB0byBmb2N1cyBvbiByZWxhdGl2ZWx5IGxpbWl0ZWQgd29yZCBjaG9pY2VzLiBTYW1lIGFzIFByZXNpZGVudCBCdXNoLCBQcmVzaWRlbnQgVHJ1bXAgYWxzbyB1c2VkIGEgbG90IG9mICd3aWxsJy4KCk5vdywgbGV0J3MgaGF2ZSBhIGNsb3NlciBsb29rIG9mIHRoZSBjb250ZW50IG9mIHRoZWlyIHNwZWVjaGVzLiBXZSBsb29rIGF0IHRoZSBzaG9ydGVyIHNlbnRlbmNlcyBmcm9tIGluYXVndXJhdGlvbiBzcGVlY2hlcyBvZiBib3RoIEdlb3JnZSBCdXNoIGFuZCBEb25hbGQgVHJ1bXAuCmBgYHtyfQpzZW50ZW5jZS5saXN0JT4lCiAgZmlsdGVyKEZpbGU9PSJHZW9yZ2VCdXNoIiwgCiAgICAgICAgIHR5cGU9PSJpbmF1ZyIsIAogICAgICAgICB3b3JkLmNvdW50PD01KSU+JQogIHNlbGVjdChzZW50ZW5jZXMpJT4lc2FtcGxlX24oMTApCgpzZW50ZW5jZS5saXN0JT4lCiAgZmlsdGVyKEZpbGU9PSJEb25hbGRKVHJ1bXAiLCAKICAgICAgICAgdHlwZT09ImluYXVnIiwgCiAgICAgICAgIHdvcmQuY291bnQ8PTUpJT4lCiAgc2VsZWN0KHNlbnRlbmNlcyklPiVzYW1wbGVfbigxMCkKYGBgClRoZSBsZWZ0IHRhYmxlIHNob3dzIHRoZSBzZW50ZW5jZXMgd2l0aCA1IHdvcmRzIG9yIGZld2VyIGZyb20gUHJlc2lkZW50IEJ1c2ggYW5kIHRoZSByaWdodCB0YWJsZSBzaG93cyB0aGF0IG9mIFByZXNpZGVudCBUcnVtcC4gQm90aCBQcmVzaWRlbnQgQnVzaCBhbmQgUHJlc2lkZW50IFRydW1wIHVzZWQgYSBsb3Qgb2YgdGhhbmsgeW91IGluIGhpcyBzaG9ydGVyIHNlbnRlbmNlcy4gUHJlc2lkZW50IFRydW1wIG1lbnRpb25lZCBoaXMgY29yZSBwb2xpY3ksIEFtZXJpY2FuIGZpcnN0LCBhIGxvdCBpbiBoaXMgc3BlZWNoLiBBcyB3ZSBjYW4gc2VlIGZyb20gYWJvdmUsIGFsdGhvdWdoIGJvdGggcHJlc2lkZW50cyB1c2VkIGEgbG90IG9mIHNob3J0IHNlbnRlbmNlcywgdGhlaXIgY29udGVudHMgYXJlIHNpZ25pZmljYW50IGRpZmZlcmVudC4gVGhlIHNob3J0IHNlbnRlbmNlcyBvZiBQcmVzaWRlbnQgQnVzaCBhcmUgYWJvdXQgIndhciIsICJwYXJlbnQiLCAiY29tcHJvbWlzZSIsIGFuZCAiZGlzc2Vuc2lvbiIgd2hpbGUgdGhlIHNob3J0IHNlbnRlbmNlcyBvZiBQcmVzaWRlbnQgVHJ1bXAgYXJlIHJlbGF0aXZlbHkgbWVhbmxlc3MsIHN1Y2ggYXMgJ25vdCBmYWlsJywgJ2NlbGVicmF0aW9uJywgJ2RheScsIGFuZCAnYmxlc3MnLgoKTm93LCBsZXQncyBpbnZlc3RpZ2F0ZSB0aGUgcHJlc2lkZW50cyB3aG8gdXNlIHRoZSBzaG9ydGVzdCBzZW50ZW5jZXMgaW4gYm90aCBwYXJ0aWVzLgpgYGB7cn0KbGVuZ3RoLmFsbCA8LSBjKCkKZm9yKGkgaW4gMTo1OCl7CiAgbGVuZ3RoLmFsbCA9IGMobGVuZ3RoLmFsbCwgbWVhbihzZW50ZW5jZS5sZW5ndGgoaSwgc3BlZWNoLmxpc3QpKSkKfQpsZW5ndGguZGVtIDwtIGMoKQpmb3IoaSBpbiBkZW1vY3JhdGljLnNwZWVjaC5pbmQpewogIGxlbmd0aC5kZW0gPSAgYyhsZW5ndGguZGVtLCBtZWFuKHNlbnRlbmNlLmxlbmd0aChpLCBzcGVlY2gubGlzdCkpKQp9Cmxlbmd0aC5yZXAgPSBjKCkKZm9yKGkgaW4gcmVwdWJsaWNhbi5zcGVlY2guaW5kKXsKICBsZW5ndGgucmVwID0gIGMobGVuZ3RoLnJlcCwgbWVhbihzZW50ZW5jZS5sZW5ndGgoaSwgc3BlZWNoLmxpc3QpKSkKfQoKI2dncGxvdCgpKwojICBnZW9tX2xpbmUoYWVzKHJlcHVibGljYW4uc3BlZWNoLmluZCwgbGVuZ3RoLnJlcCwgY29sb3IgPSAncmVwdWJsaWNhbicpKSsKIyAgZ2VvbV9saW5lKGFlcyhkZW1vY3JhdGljLnNwZWVjaC5pbmQsIGxlbmd0aC5kZW0sIGNvbG9yID0gJ2RlbW9jcmF0aWMnKSkKCnJlcHVibGljYW5bd2hpY2gubWluKGxlbmd0aC5yZXApXSAjR2VvcmdlQnVzaCBzaG9ydGVzdCBzZW50ZW5jZSwgZGlkbid0IGdvIHRvIGdyYWQgc2Nob29sLCA2NCB5ZWFycyBvbGQKaW50ZXJzZWN0KG5vLmdyYWQsIHJlcHVibGljYW5bd2hpY2gubWluKGxlbmd0aC5yZXApXSkKCnogPSBsZW5ndGgucmVwCnpbd2hpY2gubWluKGxlbmd0aC5yZXApXSA9IE5BCnJlcHVibGljYW5bd2hpY2gubWluKHopXSAjRG9uYWxkSlRydW1wIHNlY29uZCBzaG9ydGVzdCBzZW50ZW5jZSwgZGlkbid0IGdvIHRvIGdyYWQgc2Nob29sLCA3MCB5ZWFycyBvbGQKaW50ZXJzZWN0KG5vLmdyYWQsIHJlcHVibGljYW5bd2hpY2gubWluKHopXSkKCmRlbW9jcmF0aWNbd2hpY2gubWluKGxlbmd0aC5kZW0pXSAjTHluZG9uQkpvaG5zb24sIDY0IHllYXJzIG9sZCAKaW50ZXJzZWN0KG5vLmdyYWQsIGRlbW9jcmF0aWNbd2hpY2gubWluKGxlbmd0aC5kZW0pXSkgI3dlbnQgdG8gZ3JhZCBzY2hvb2wKCnoxID0gbGVuZ3RoLmRlbQp6MVt3aGljaC5taW4obGVuZ3RoLmRlbSldID0gTkEKZGVtb2NyYXRpY1t3aGljaC5taW4oejEpXSAjV2lsbGlhbUpDbGludG9uLCA0NiB5ZWFycyBvbGQKaW50ZXJzZWN0KG5vLmdyYWQsIGRlbW9jcmF0aWNbd2hpY2gubWluKHoxKV0gKQpgYGAKRnJvbSB0aGlzIHBhcnQsIHdlIHNlZSBib3RoIHBhcnRpZXMgaGF2ZSBhIGRlY3JlYXNpbmcgdHJlbmQgb2YgbnVtYmVyIG9mIHdvcmRzIGluIGVhY2ggc2VudGVuY2UuIEludGVyZXN0aW5nbHksIHdlIGZvdW5kIGJvdGggb2YgdHdvIHJlcHVibGljYW4gcHJlc2lkZW50cyB3aG8gdXNlIHRoZSBzaG9ydGVzdCBzZW50ZW5jZXMgZGlkIG5vdCBhdHRlbmQgZ3JhZHVhdGUgc2Nob29sIHdoaWxlIGJvdGggb2YgdGhlIGRlbW9jcmF0aWMgcHJlc2lkZW50cyB3aG8gdXNlIHRoZSBzaG9ydGVzdCBzZW50ZW5jZXMgYXR0ZW5kZWQgZ3JhZHVhdGUgc2Nob29sLiAKCldlIHRoZW4gc3VzcGVjdCBpZiB0aGVyZSBpcyBhbm90aGVyIGZhY3RvciBhZmZlY3RpbmcgdGhlIGxlbmd0aCBvZiBzZW50ZW5jZXMuIFdlIHNlYXJjaGVkIHRoZSBhZ2Ugb2YgdGhlIGZvdXIgcHJlc2lkZW50cywgYW5kIGZvdW5kIHByZXNpZGVudCBUcnVtcCB3YXMgNzAgeWVhcnMgb2xkIGFuZCBwcmVzaWRlbnQgQnVzaCB3YXMgNjQgeWVhcnMgb2xkIHdoaWxlIHByZXNpZGVudCBDbGludG9uIHdhcyA0NiB5ZWFycyBvbGQgYW5kIHByZXNpZGVudCBKb2huc29uIHdhcyA2NCB5ZWFycyBvbGQgd2hlbiB0aGV5IGdhdmUgdGhlIGluYXVndXJhdGlvbiBzcGVlY2guIFdlIHN1c3BlY3QgdGhhdCB3aWxsIHRoZSBsZW5ndGggb2Ygc2VudGVuY2UgY29ycmVsYXRlIHRvIHRoZSBhZ2Ugb2YgdGhlIHByZXNpZGVudHMuIEhlcmUsIHdlIHVzZWQgdGhlIGRhdGEgZnJvbSBXaWtpcGVkaWEuIChodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9MaXN0X29mX3ByZXNpZGVudHNfb2ZfdGhlX1VuaXRlZF9TdGF0ZXNfYnlfYWdlKQpgYGB7cn0KIyBQcmVzaWRlbnRzIHRoYXQgdXNlIHNob3J0ZXIgc2VudGVuY2VzCmFnZS5uYW1lID0gYygnR2VvcmdlQnVzaCcsJ0RvbmFsZEpUcnVtcCcsJ0x5bmRvbkJKb2huc29uJywnR2VvcmdlV0J1c2gnLCdXaWxsaWFtSkNsaW50b24nLCdSb25hbGRSZWFnYW4nLCdSaWNoYXJkTml4b24nLCdGcmFua2xpbkRSb29zZXZlbHQnLCdIYXJyeVNUcnVtYW4nLCdEd2lnaHRERWlzZW5ob3dlcicsJ0JhcmFja09iYW1hJywnSGVyYmVydEhvb3ZlcicsJ0ppbW15Q2FydGVyJywnV2FycmVuR0hhcmRpbmcnKQoKIyBBZ2Ugb2YgdGhlIHByZXNpZGVudHMgdGhhdCB1c2Ugc2hvcnRlciBzZW50ZW5jZXMKYWdlID0gYyg2NCwgNzAsIDY0LCA1NCwgNDYsIDY5LCA1NiwgNTEsIDYwLCA2MiwgNDcsIDU0LCA1MiwgNTUpCmNhdCgnbWVkaWFuIGFnZSBvZiBwcmVzaWRlbnQgd2l0aCBzaG9ydGVyIHNlbnRlbmNlOicsIG1lZGlhbihhZ2UpKQpgYGAKQWNjb3JkaW5nIHRvIFdpa2lwZWRpYSwgdGhlIG1lZGlhbiBhZ2Ugb2YgcHJlc2lkZW50cyB3aGVuIHRoZXkgZW50ZXJlZCB0aGUgV2hpdGUgSG91c2UgaXMgNTUuNiB5ZWFycyBvbGQsIHdoaWNoIGlzIGNsb3NlIHRvIHRoZSBtZWRpYW4gYWdlIG9mIHRoZSBhYm92ZSBkYXRhIHdlIGZvdW5kLiBIZW5jZSwgdGhlcmUgaXMgbm90IGEgY29ycmVsYXRpb24gYmV0d2VlbiBhZ2UgYW5kIGxlbmd0aCBvZiBzZW50ZW5jZXMuCgpOb3csIGxldCdzIGludmVzdGlnYXRlIGlmIHRoZXJlIGlzIGEgZGlmZmVyZW5jZSBpbiBudW1iZXIgb2Ygd29yZHMgaW4gZWFjaCBzZW50ZW5jZSBiZXR3ZWVuIGZpcnN0IGFuZCBzZWNvbmQgdGVybS4KYGBge3J9CmZpcnN0LnRlcm0gPSBzcGVlY2gubGlzdCRGaWxlW3doaWNoKHNwZWVjaC5saXN0JFRlcm09PTEpXQpmaXJzdC50ZXJtLmluZCA9IHdoaWNoKHNwZWVjaC5saXN0JFRlcm09PTEpCnNlY29uZC50ZXJtID0gc3BlZWNoLmxpc3QkRmlsZVt3aGljaChzcGVlY2gubGlzdCRUZXJtPT0yKV0Kc2Vjb25kLnRlcm0uaW5kID0gd2hpY2goc3BlZWNoLmxpc3QkVGVybT09MikKCm1lYW4uZmlyc3QudGVybS5zZW50ZW5jZS5sZW5ndGggPSAwCmZvcihpIGluIGZpcnN0LnRlcm0uaW5kKXsKICBtZWFuLmZpcnN0LnRlcm0uc2VudGVuY2UubGVuZ3RoID0gbWVhbi5maXJzdC50ZXJtLnNlbnRlbmNlLmxlbmd0aCArIG1lYW4oc2VudGVuY2UubGVuZ3RoKGksIHNwZWVjaC5saXN0KSkKfQptZWFuLmZpcnN0LnRlcm0uc2VudGVuY2UubGVuZ3RoID0gbWVhbi5maXJzdC50ZXJtLnNlbnRlbmNlLmxlbmd0aC9sZW5ndGgoZmlyc3QudGVybS5pbmQpIAoKbWVhbi5zZWNvbmQudGVybS5zZW50ZW5jZS5sZW5ndGggPSAwCmZvcihpIGluIHNlY29uZC50ZXJtLmluZCl7CiAgbWVhbi5zZWNvbmQudGVybS5zZW50ZW5jZS5sZW5ndGggPSBtZWFuLnNlY29uZC50ZXJtLnNlbnRlbmNlLmxlbmd0aCArIG1lYW4oc2VudGVuY2UubGVuZ3RoKGksIHNwZWVjaC5saXN0KSkKfQptZWFuLnNlY29uZC50ZXJtLnNlbnRlbmNlLmxlbmd0aCA9IG1lYW4uc2Vjb25kLnRlcm0uc2VudGVuY2UubGVuZ3RoL2xlbmd0aChzZWNvbmQudGVybS5pbmQpIAoKY2F0KCdhdmVyYWdlIG51bWJlciBvZiB3b3JkcyBpbiBlYWNoIHNlbnRlbmNlIGZvciBmaXJzdCB0ZXJtJywgbWVhbi5maXJzdC50ZXJtLnNlbnRlbmNlLmxlbmd0aCwnXG4nKQpjYXQoJ2F2ZXJhZ2UgbnVtYmVyIG9mIHdvcmRzIGluIGVhY2ggc2VudGVuY2UgZm9yIHNlY29uZCB0ZXJtJywgbWVhbi5zZWNvbmQudGVybS5zZW50ZW5jZS5sZW5ndGgsJ1xuJykKYGBgClRoZXJlZm9yZSwgdGhlcmUgaXMgbm90IGEgc2lnbmlmaWNhbnQgZGlmZmVyZW5jZSBpbiBiZXR3ZWVuIGluYXVndXJhdGlvbiBzcGVlY2ggb2YgZmlyc3QgYW5kIHNlY29uZCB0ZXJtLgoKU3VtbWFyeToKSW4gcGFydCAzLjEsIHdlIGZvdW5kIHRoZSBhdmVyYWdlIHNlbnRlbmNlIGxlbmd0aCBmb3IgcmVwdWJsaWNhbiBwcmVzaWRlbnRzIGFyZSBsb3dlciB0aGFuIGRlbW9jcmF0aWMgcHJlc2lkZW50cywgYW5kIHRoaXMgbWF5IGR1ZSB0byB0aGUgZmFjdCB0aGF0IHRoZXJlIGFyZSBmZXdlciByZXB1YmxpY2FuIHByZXNpZG5ldHMgYXR0ZW5kZWQgZ3JhZHVhdGUgc2Nob29sIGFzIGNvbXBhcmVkIHRvIGRlbW9jcmF0aWMgcHJlc2lkZW50cy4gV2UgYWxzbyBmb3VuZCBnb2luZyB0byBncmFkdWF0ZSBzY2hvb2wgYmVmb3JlIDE4OTAgaGFzIGEgc3Ryb25nZXIgZWZmZWN0IG9uIGxlbmd0aCBvZiBzZW50ZW5jZXMuIAoKIyMgU3RlcCAzLjIgRGF0YSBBbmFseXRpY3MgLSBMZW5ndGggb2YgZWFjaCB3b3JkCkFmdGVyIGFuYWx5emluZyBzZW50ZW5jZSBsZW5ndGggb2YgcHJlc2lkZW50IGluYXVndXJhdGlvbiBzcGVlY2hlcywgbGV0J3MgaW52ZXN0aWdhdGUgdGhlIGxlbmd0aCBvZiB0aGUgd29yZCB0aGF0IHRoZSBwcmVzaWRlbnRzIHVzZS4gSGVyZSwgd2UgcHJlZGljdCBhdHRlbmRpbmcgZ3JhZHVhdGUgc2Nob29sIG1heSBiZSBjb3JyZWxhdGVkIHdpdGggdGhlIGxlbmd0aCBvZiB0aGUgd29yZCB0aGF0IGEgcHJlc2lkZW50IHVzZSBzdWNoIHRoYXQgYSBwcmVzaWRlbnQgd2hvIGF0dGVuZGVkIGdyYWR1YXRlIHNjaG9vbCBtYXkgdXNlIGEgbG9uZ2VyIHdvcmQuCgpXZSBkZWZpbmUgYSBmdW5jdGlvbiB0byBjb3VudCB0aGUgbnVtYmVyIG9mIGNoYXJhY3RlciBpbiBlYWNoIHdvcmQuIFNpbmNlIHdlIGFyZSBpbnRlcmVzdGVkIGluIHRoZSBhdmVyYWdlIGxlbmd0aCBvZiBiaWcgd29yZHMgdGhhdCBwcmVzaWRlbnRzIHVzZSwgd2UgZG8gbm90IGNvbnNpZGVyIHdvcmRzIHdpdGggbGVzcyB0aGFuIGZpdmUgbGV0dGVycy4KYGBge3J9CndvcmQubGVuZ3RoIDwtIGZ1bmN0aW9uKGluZGV4LCBkZil7CiAgc3BlZWNoLnZlYyA9IGRmJGZ1bGx0ZXh0CiAgYSA9IHN0cnNwbGl0KHNwZWVjaC52ZWNbaW5kZXhdLCAnXFxzJykKICByZXMudmVjID0gYygpCiAgZm9yKGogaW4gMTpsZW5ndGgoYVtbMV1dKSl7CiAgICByZXMudmVjID0gYyhyZXMudmVjLCBuY2hhcihhW1sxXV1bW2pdXSkpCiAgfQogIHJlcy52ZWMgPSAocmVzLnZlY1tyZXMudmVjID4gNV0pCiAgcmV0dXJuKHJlcy52ZWMpCn0KYGBgCgpBZ2Fpbiwgc2FtZSBhcyBiZWZvcmUsIGxldCdzIHNlZSBpZiB0aGVyZSBpcyBkaWZmZXJlbmNlIGluIHRoZSBhdmVyYWdlIHdvcmQgbGVuZ3RoCmJldHdlZW4gcmVwdWJsaWNhbiBhbmQgZGVtb2NyYXRpYyBwcmVzaWRlbnRzLgpgYGB7cn0KIyB3b3JkIGxlbmd0aCBvZiByZXB1YmxpY2FuIGFuZCBkZW1vY3JhdGljIAp3b3JkLmxlbmd0aC5kZW0gPC0gYygpCmZvcihpIGluIGRlbW9jcmF0aWMuc3BlZWNoLmluZCl7CiAgd29yZC5sZW5ndGguZGVtID0gIGMod29yZC5sZW5ndGguZGVtLCBtZWFuKHdvcmQubGVuZ3RoKGksIHNwZWVjaC5saXN0KSkpCn0Kd29yZC5sZW5ndGgucmVwID0gYygpCmZvcihpIGluIHJlcHVibGljYW4uc3BlZWNoLmluZCl7CiAgd29yZC5sZW5ndGgucmVwID0gIGMod29yZC5sZW5ndGgucmVwLCBtZWFuKHdvcmQubGVuZ3RoKGksIHNwZWVjaC5saXN0KSkpCn0KCmNhdCgnYXZlcmFnZSB3b3JkIGxlbmd0aCBvZiByZXB1YmxpY2FuIHByZXNpZGVudHM6JywgbWVhbih3b3JkLmxlbmd0aC5yZXApLCAnXG4nKQpjYXQoJ2F2ZXJhZ2Ugd29yZCBsZW5ndGggb2YgZGVtb2NyYXRpYyBwcmVzaWRlbnRzOicsIG1lYW4od29yZC5sZW5ndGguZGVtKSwgJ1xuJykKYGBgClRoZSBhdmVyYWdlIHdvcmQgbGVuZ3RoIG9mIGJvdGggcGFydGllcyBhcmUgdmVyeSBzaW1pbGFyLiBUaGVuLCBuZXh0IGxvb2sgYXQgd2hldGhlciBnb2luZyB0byBncmFkdWF0ZSBzY2hvb2wgaGFzIGFuIGVmZmVjdCBvbiBhdmVyYWdlIHdvcmQgbGVuZ3RoLgoKYGBge3J9Cm5vLmdyYWQud29yZC5sZW5ndGggPC0gMApmb3IoaSBpbiBuby5ncmFkLmExODkwLmluZCl7CiAgbm8uZ3JhZC53b3JkLmxlbmd0aCA9IG5vLmdyYWQud29yZC5sZW5ndGggKyBtZWFuKHdvcmQubGVuZ3RoKGksc3BlZWNoLmxpc3QpKQp9Cm5vLmdyYWQud29yZC5sZW5ndGggPSAobm8uZ3JhZC53b3JkLmxlbmd0aCkvbGVuZ3RoKG5vLmdyYWQuYTE4OTAuaW5kKQoKZ3JhZC53b3JkLmxlbmd0aCA8LSAwCmZvcihpIGluIGdyYWQuYTE4OTAuaW5kKXsKICBncmFkLndvcmQubGVuZ3RoID0gZ3JhZC53b3JkLmxlbmd0aCArIG1lYW4od29yZC5sZW5ndGgoaSxzcGVlY2gubGlzdCkpCn0KZ3JhZC53b3JkLmxlbmd0aCA9IChncmFkLndvcmQubGVuZ3RoKS9sZW5ndGgoZ3JhZC5hMTg5MC5pbmQpCgpjYXQoJ2F2ZXJhZ2Ugd29yZCBsZW5ndGggb2YgcHJlc2lkZW50cyB3aG8gYXR0ZW5kZWQgZ3JhZHVhdGUgc2Nob29sOicsZ3JhZC53b3JkLmxlbmd0aCwnXG4nKQpjYXQoJ2F2ZXJhZ2Ugd29yZCBsZW5ndGggb2YgcHJlc2lkZW50cyB3aG8gZGlkIG5vdCBhdHRlbmQgZ3JhZHVhdGUgc2Nob29sOicsbm8uZ3JhZC53b3JkLmxlbmd0aCwnXG4nKQpgYGAKQWdhaW4sIHRoZXJlIGlzIG5vdCBhIHNpZ25pZmljYW50IGRpZmZlcmVuY2UuCgpTdW1tYXJ5OgpJbiBwYXJ0IDMuMiwgd2UgY29uY2x1ZGUgdGhlcmUgYXJlIG5vdCBhIHNpZ25pZmljYW50IGRpZmZlcmVuY2UgaW4gYXZlcmFnZSB3b3JkIGxlbmd0aCBpbiBiZXR3ZWVuIHRoZSB0d28gcGFydGllcyBhcyB3ZWxsIGFzIGluIGJldHdlZW4gcHJlc2lkZW50cyB3aG8gYXR0ZW5kZWQgZ3JhZHVhdGUgc2Nob29sIGFuZCBwcmVzaWRlbnRzIHdobyBkaWQgbm90IGF0dGVuZCBncmFkdWF0ZSBzY2hvb2wuCgojIyBTdGVwIDMuMyBEYXRhIEFuYWx5dGljcyAtIFNlbnRpbWVudCBBbmFseXNpcwpBZnRlciBhbmFseXppbmcgYm90aCB3b3JkIGxlbmd0aCBhbmQgc2VudGVuY2UgbGVuZ3RoLCBsZXQncyBkaWcgZGVlcGVyIGFuZCBzdHVkeSB0aGUgZW1vdGlvbiBvZiB0aGUgaW5hdWd1cmF0aW9uIHNwZWVjaGVzLgoKRmlyc3QsIGxldCdzIHRha2UgYSBsb29rIG9mIHRoZSBvdmVyYWxsIGVtb3Rpb24gb2YgYWxsIHRoZSBwcmVzaWRlbnRpYWwgaW5hdWd1cmF0aW9uIHNwZWVjaGVzLgpgYGB7cn0KZW1vLm1lYW5zPWNvbE1lYW5zKHNlbGVjdChzZW50ZW5jZS5saXN0LCBhbmdlcjp0cnVzdCk+MC4wMSkKY29sLnVzZT1jKCJyZWQyIiwgImRhcmtnb2xkZW5yb2QxIiwgCiAgICAgICAgICAgICJjaGFydHJldXNlMyIsICJibHVldmlvbGV0IiwKICAgICAgICAgICAgImRhcmtnb2xkZW5yb2QyIiwgImRvZGdlcmJsdWUzIiwgCiAgICAgICAgICAgICJkYXJrZ29sZGVucm9kMSIsICJkYXJrZ29sZGVucm9kMSIpCmJhcnBsb3QoZW1vLm1lYW5zW29yZGVyKGVtby5tZWFucyldLCBsYXM9MiwgY29sPWNvbC51c2Vbb3JkZXIoZW1vLm1lYW5zKV0sIGhvcml6PVQsIG1haW49IkluYXVndXJhbCBTcGVlY2hlcyIpCmBgYApGcm9tIHRoZSBhYm92ZSBncmFwaCwgd2Ugc2VlIG1vc3Qgb2YgdGhlIHByZXNpZGVudHMgbGlrZSB0byB1c2Ugd29yZHMgdGhhdCBhcmUgcmVsYXRlZCB0byB0cnVzdCwgYW50aWNpcGF0aW9uLCBhbmQgam95IGluIHRoZWlyIGluYXVndXJhdGlvbiBzcGVlY2guIFRoZW4sIGxldCdzIHRha2UgYSBsb29rIHRvIHNlZSBpZiB0aGUgcHJvcG9ydGlvbiBvZiBlYWNoIGVtb3Rpb24gY2hhbmdlcyBvdmVyIHRoZSBoaXN0b3J5LgpgYGB7cn0KYW5nZXIgPSBjKCk7IGFudGljaXBhdGlvbiA9YygpOyBkaXNndXN0PWMoKTsgZmVhciA9YygpOyBqb3k9YygpOyBzYWRuZXNzPWMoKTsgc3VycHJpc2U9YygpO3RydXN0PWMoKTtuZWdhdGl2ZT1jKCk7cG9zaXRpdmU9YygpCgpmb3IoaSBpbiAxOjU4KXsKICByYW4uaW5kID0gd2hpY2goc2VudGVuY2UubGlzdCRGaWxlID09IHNwZWVjaC5saXN0JEZpbGVbaV0pCiAgYW5nZXIgPSBjKGFuZ2VyLCBhcHBseShzZW50ZW5jZS5saXN0W3Jhbi5pbmQsMTM6MjJdLDIsIG1lYW4pWzFdKQogIGFudGljaXBhdGlvbiA9IGMoYW50aWNpcGF0aW9uLCBhcHBseShzZW50ZW5jZS5saXN0W3Jhbi5pbmQsMTM6MjJdLDIsIG1lYW4pWzJdKQogIGRpc2d1c3QgPSBjKGRpc2d1c3QsIGFwcGx5KHNlbnRlbmNlLmxpc3RbcmFuLmluZCwxMzoyMl0sMiwgbWVhbilbM10pCiAgZmVhciA9IGMoZmVhciwgYXBwbHkoc2VudGVuY2UubGlzdFtyYW4uaW5kLDEzOjIyXSwyLCBtZWFuKVs0XSkKICBqb3kgPSBjKGpveSwgYXBwbHkoc2VudGVuY2UubGlzdFtyYW4uaW5kLDEzOjIyXSwyLCBtZWFuKVs1XSkKICBzYWRuZXNzID0gYyhzYWRuZXNzLCBhcHBseShzZW50ZW5jZS5saXN0W3Jhbi5pbmQsMTM6MjJdLDIsIG1lYW4pWzZdKQogIHN1cnByaXNlID0gYyhzdXJwcmlzZSwgYXBwbHkoc2VudGVuY2UubGlzdFtyYW4uaW5kLDEzOjIyXSwyLCBtZWFuKVs3XSkKICB0cnVzdCA9IGModHJ1c3QsIGFwcGx5KHNlbnRlbmNlLmxpc3RbcmFuLmluZCwxMzoyMl0sMiwgbWVhbilbOF0pCiAgbmVnYXRpdmUgPSBjKG5lZ2F0aXZlLCBhcHBseShzZW50ZW5jZS5saXN0W3Jhbi5pbmQsMTM6MjJdLDIsIG1lYW4pWzldKQogIHBvc2l0aXZlID0gYyhwb3NpdGl2ZSwgYXBwbHkoc2VudGVuY2UubGlzdFtyYW4uaW5kLDEzOjIyXSwyLCBtZWFuKVsxMF0pCn0KZ2dwbG90KCkrCiAgZ2VvbV9saW5lKGFlcyh4PTE6NTgseT1hbmdlcixjb2xvcj0nYW5nZXInKSkrCiAgZ2VvbV9saW5lKGFlcyh4PTE6NTgseT1hbnRpY2lwYXRpb24sY29sb3I9J2FudGljaXBhdGlvbicpKSsKICBnZW9tX2xpbmUoYWVzKHg9MTo1OCx5PWRpc2d1c3QsY29sb3I9J2Rpc2d1c3QnKSkrCiAgZ2VvbV9saW5lKGFlcyh4PTE6NTgseT1mZWFyLGNvbG9yPSdmZWFyJykpKwogIGdlb21fbGluZShhZXMoeD0xOjU4LHk9am95LGNvbG9yPSdqb3knKSkrCiAgZ2VvbV9saW5lKGFlcyh4PTE6NTgseT1zYWRuZXNzLGNvbG9yPSdzYWRuZXNzJykpKwogIGdlb21fbGluZShhZXMoeD0xOjU4LHk9c3VycHJpc2UsY29sb3I9J3N1cnByaXNlJykpKwogIGdlb21fbGluZShhZXMoeD0xOjU4LHk9dHJ1c3QsY29sb3I9J3RydXN0JykpKwogIGdlb21fbGluZShhZXMoeD0xOjU4LHk9bmVnYXRpdmUsY29sb3I9J25lZ2F0aXZlJykpKwogIGdlb21fbGluZShhZXMoeD0xOjU4LHk9cG9zaXRpdmUsY29sb3I9J3Bvc2l0aXZlJykpKwogIHlsYWIoJycpCmBgYApUaGUgb3ZlcmFsbCB0cmVuZGluZyBvZiBlYWNoIGVtb3Rpb24gcmVtYWluIHJlbGF0aXZlbHkgc3RhYmxlIGV4Y2VwdCB3ZSBzZWUgYSBkcm9wIGluICdwb3NpdGl2ZScsICdhbnRpY2lwYXRlJywgYW5kICd0cnVzdCcgd29yZHMgYW5kIGEgcmFpc2UgaW4gJ25lZ2F0aXZlJywgJ2ZlYXInLCAnYW5nZXInLCBhbmQgJ3NhZG5lc3MnIHdvcmRzLCB3aGljaCBoYXBwZW5lZCBhdCB3aGVuIHRoZSBpbmF1Z3VyYXRpb24gc3BlZWNoIG9mIEFicmFoYW0gTGluY29sbiB3YXMgbWFkZS4gUHJlc2lkZW50cyBMaW5jb2xuIGxlZCB0aGUgVVMgdGhyb3VnaCBDaXZpbCBXYXIsIHdoaWNoIGlzIG9mdGVuIGRlc2NyaWJlZCBhcyB0aGUgYmxvb2RpZXN0IHdhciBpbiB0aGUgVVMuIFRoaXMgbWF5IGV4cGxhaW4gdGhlIGluY3JlYXNlZCBpbiBuZWdhdGl2ZSB3b3JkcyB3aXRoaW4gdGhpcyBwZXJpb2Qgb2YgdGltZS4gQWxzbywgd2Ugc2VlIGEgcmFpc2UgaW4gJ3Bvc2l0aXZlJywgJ2pveScsIGFuZCAndHJ1c3QnIHdvcmRzIGluIHRoZSBpbmF1Z3VyYXRpb24gc3BlZWNoIG9mIEhhcnJ5IFMuIFRydW1hbi4gUHJlc2lkZW50IFRydW1hbiBsZWQgVVMgdG93YXJkIHRoZSB2aWN0b3J5IG9mIFdvcmxkIFdhciBJSSwgd2hpY2ggbWF5IGV4cGxhaW4gdGhlIHJhaXNlIG9mIHRoZSBwb3NpdGl2ZSBlbW90aW9uIHdvcmRzIGluIGhpcyBpbmF1Z3VyYXRpb24gc3BlZWNoLgoKTmV4dCwgd2UgY2FuIGludmVzdGlnYXRlIHRoZSBkaWZmZXJlbmNlIGluIGVtb3Rpb24gZXhwcmVzc2VkIGJ5IHByZXNpZGVudHMgaW4gYm90aCBwYXJ0aWVzLiBXZSByYW5kb21seSBzZWxlY3QgYSBmZXcgcHJlc2lkZW50cyBmcm9tIGVhY2ggcGFydHkuCmBgYHtyfQojIE5vdywgbGV0cyBsb29rIGF0IHRoZSBlbW90aW9uIG9mIHNvbWUgcmVwIHByZXNpZGVudHMKcmFuZG9tLnJlcD1jKCdSaWNoYXJkTml4b24nLCdSb25hbGRSZWFnYW4nLCdHZW9yZ2VCdXNoJywnR2VvcmdlV0J1c2gnLCdEb25hbGRKVHJ1bXAnKQpwYXIobWZyb3cgPSBjKDMsIDIpKQpmb3IoaSBpbiByYW5kb20ucmVwKXsKICByYW4uaW5kID0gd2hpY2goc2VudGVuY2UubGlzdCRGaWxlID09IGkpCiAgZW1vLm1lYW5zPWNvbE1lYW5zKHNlbGVjdChzZW50ZW5jZS5saXN0W3Jhbi5pbmQsXSwgYW5nZXI6dHJ1c3QpPjAuMDEpCmNvbC51c2U9YygicmVkMiIsICJkYXJrZ29sZGVucm9kMSIsIAogICAgICAgICAgICAiY2hhcnRyZXVzZTMiLCAiYmx1ZXZpb2xldCIsCiAgICAgICAgICAgICJkYXJrZ29sZGVucm9kMiIsICJkb2RnZXJibHVlMyIsIAogICAgICAgICAgICAiZGFya2dvbGRlbnJvZDEiLCAiZGFya2dvbGRlbnJvZDEiKQogIGJhcnBsb3QoZW1vLm1lYW5zW29yZGVyKGVtby5tZWFucyldLCBsYXM9MiwgY29sPWNvbC51c2Vbb3JkZXIoZW1vLm1lYW5zKV0sIGhvcml6PVQsIG1haW49aSkKfQoKIyBsZXRzIGxvb2sgYXQgdGhlIGVtb3Rpb24gb2Ygc29tZSBkZW0gcHJlc2lkZW50cwpyYW5kb20uZGVtID0gYygnRnJhbmtsaW5EUm9vc2V2ZWx0JywnSm9obkZLZW5uZWR5JywnTHluZG9uQkpvaG5zb24nLCdXaWxsaWFtSkNsaW50b24nLCAnQmFyYWNrT2JhbWEnKQpwYXIobWZyb3cgPSBjKDMsMikpCmZvcihpIGluIHJhbmRvbS5kZW0pewogIHJhbi5pbmQgPSB3aGljaChzZW50ZW5jZS5saXN0JEZpbGUgPT0gaSkKICBlbW8ubWVhbnM9Y29sTWVhbnMoc2VsZWN0KHNlbnRlbmNlLmxpc3RbcmFuLmluZCxdLCBhbmdlcjp0cnVzdCk+MC4wMSkKY29sLnVzZT1jKCJyZWQyIiwgImRhcmtnb2xkZW5yb2QxIiwgCiAgICAgICAgICAgICJjaGFydHJldXNlMyIsICJibHVldmlvbGV0IiwKICAgICAgICAgICAgImRhcmtnb2xkZW5yb2QyIiwgImRvZGdlcmJsdWUzIiwgCiAgICAgICAgICAgICJkYXJrZ29sZGVucm9kMSIsICJkYXJrZ29sZGVucm9kMSIpCiAgYmFycGxvdChlbW8ubWVhbnNbb3JkZXIoZW1vLm1lYW5zKV0sIGxhcz0yLCBjb2w9Y29sLnVzZVtvcmRlcihlbW8ubWVhbnMpXSwgaG9yaXo9VCwgbWFpbj1pKQp9CmBgYApJbnRlcmVzdGx5LCB3ZSBmb3VuZCB0aGUgZW1vdGlvbiBpbiB0aGUgaW5hdWd1cmF0aW9uIHNwZWVjaGVzIG9mIGRlbW9jcmF0aWMgcHJlc2lkZW50cyBhcmUgdmVyeSBjb25zaXN0ZW50IHdoaWxlIHRoZSBlbW90aW9uIG9mIHJlcHVibGljYW4gcHJlc2lkZW50cycgaW5hdWd1cmF0aW9uIHNwZWVjaGVzIHZhcmllcyBhbW9uZyBkaWZmZXJlbnQgcHJlc2lkZW50cy4gCgpOZXh0LCB3ZSBpbnZlc3RpZ2F0ZSB0aGUgZW1vdGlvbiBvZiBpbmF1Z3VyYXRpb24gc3BlZWNoZXMgYmV0d2VlbiBwcmVzaWRlbnQgd2hvIGF0dGVuZGVkIGdyYWR1YXRlIHNjaG9vbCBhbmQgcHJlc2lkZW50IHdobyBkaWQgbm90IGF0dGVuZCBncmFkdWF0ZSBzY2hvb2wuCmBgYHtyfQpub19ncmFkX3NjaG9vbCA9IGFwcGx5KHNlbnRlbmNlLmxpc3Rbbm8uZ3JhZC5hMTg5MC5pbmQsMTM6MjJdLDIsIG1lYW4pCmdyYWRfc2Nob29sID0gYXBwbHkoc2VudGVuY2UubGlzdFtncmFkLmExODkwLmluZCwxMzoyMl0sMiwgbWVhbikgCmJhcnBsb3QoYXMubWF0cml4KGRhdGEuZnJhbWUobm9fZ3JhZF9zY2hvb2wsZ3JhZF9zY2hvb2wpKSwgYmVzaWRlPVQsIGNvbCA9IDA6OSkKbGVnZW5kKCJ0b3BsZWZ0IiwgYygiYW5nZXIiLCJhbnRpY2lwYXRpb24iLCJkaXNndXN0IiwiZmVhciIsImpveSIsJ3NhZG5lc3MnLCdzdXJwcmlzZScsJ3RydXN0JywnbmVnYXRpdmUnLCdwb3NpdGl2ZScpLCBjZXg9MC41LCBidHk9Im4iLCBmaWxsPTA6OSkKYGBgCldlIGZvdW5kIHByZXNpZGVudHMgd2hvIGF0dGVuZGVkIGdyYWR1YXRlIHNjaG9vbCB1c2Ugc2lnbmlmaWNhbnRseSBtb3JlIHBvc2l0aXZlIHdvcmRzIGFuZCBzaWduaWZpY2FudGx5IGZld2VyIG5lZ2F0aXZlIHdvcmRzLiBQcmVzaWRlbnRzIHdobyBhdHRlbmRlZCBncmFkdWF0ZSBzY2hvb2wgdGVuZCB0byB1c2UgbW9yZSAndHJ1c3QnIHJlbGF0ZWQgd29yZHMgYW5kIGZld2VyICdzYWRuZXNzJyBhbmQgJ3N1cnByaXNlJyByZWxhdGVkIHdvcmRzLiBUaGlzIG1heSByYWlzZSB0aGUgcG9zc2liaWxpdGVzIGh5cG90aGVzaXMgb2YgcHJlc2lkZW50cyB3aG8gYXR0ZW5kIGdyYWR1YXRlIHRlbmQgdG8gZ2l2ZSBhIG1vcmUgcG9zaXRpdmUgaW5hdWd1cmF0aW9uIHNwZWVjaC4gSG93ZXZlciwgZnVydGhlciBpbnZlc3RpZ2F0aW9uIGFuZCBkYXRhIGlzIG5lZWRlZCBmb3IgYWRkaXRpb25hbCBldmlkZW5jZSBvZiB0aGlzIHByZXNwZWN0aXZlLgoKTm93LCB3ZSBpbnZlc3RpZ2F0ZSB0aGUgZW1vdGlvbiBvZiB0aGUgc2VudGVuY2VzIGluIGRpZmZlcmVudCBsZW5ndGguCmBgYHtyfQojIHNob3J0IHNlbnRlbmNlIHZzIGxvbmcgc2VudGVuY2UKc2hvcnQuaW5kID0gd2hpY2gobGVuZ3RoLmFsbFsxMTo1OF0gPD0gbWVhbihsZW5ndGguYWxsKSkKbG9uZy5pbmQgPSB3aGljaChsZW5ndGguYWxsWzExOjU4XSA+IG1lYW4obGVuZ3RoLmFsbCkpCnNob3J0ID0gYXBwbHkoc2VudGVuY2UubGlzdFtzaG9ydC5pbmQsMTM6MjJdLDIsIG1lYW4pCmxvbmcgPSBhcHBseShzZW50ZW5jZS5saXN0W2xvbmcuaW5kLDEzOjIyXSwyLCBtZWFuKQpiYXJwbG90KGFzLm1hdHJpeChkYXRhLmZyYW1lKHNob3J0LGxvbmcpKSwgYmVzaWRlPVQsIGNvbCA9IDA6OSkKbGVnZW5kKCJ0b3BsZWZ0IiwgYygiYW5nZXIiLCJhbnRpY2lwYXRpb24iLCJkaXNndXN0IiwiZmVhciIsImpveSIsJ3NhZG5lc3MnLCdzdXJwcmlzZScsJ3RydXN0JywnbmVnYXRpdmUnLCdwb3NpdGl2ZScpLCBjZXg9MC41LCBidHk9Im4iLCBmaWxsPTA6OSkKYGBgCkhlcmUsIHdlIGZvdW5kIGxvbmdlciBzZW50ZW5jZXMgdGVuZCB0byBoYXZlIGZld2VyICJuZWdhdGl2ZSIsICJzYWRuZXNzIiwgYW5kICJmZWFyIiByZWxhdGVkIHdvcmRzLgoKSW4gc3VtbWFyeSwgaW4gMy4zLCB3ZSBhbmFseXplZCBlbW90aW9uIG9mIHRoZSBpbmF1Z3VyYXRpb24gc3BlZWNoZXMuIFdlIGZvdW5kIGRlbW9jcmF0aWMgcHJlc2lkZW50cycgaW5hdWd1cmF0aW9uIHNwZWVjaGVzIGhhdmUgYSBtb3JlIGNvbnNpc3RlbnQgcHJvcG9ydGlvbiBvZiBlYWNoIGVtb3Rpb24gd2hpbGUgcmVwdWJsaWNhbiBwcmVzaWRlbnRzJyBpbmF1Z3VyYXRpb24gc3BlZWNoZXMgZG8gbm90IGhhdmUgYSBjb25zaXN0ZW50IHBhdHRlcm4uIEFsc28sIHByZXNpZGVudHMgd2hvIHdlbnQgdG8gZ3JhZHVhdGUgc2Nob29sIHRlbmQgdG8gZ2l2ZSBhIG1vcmUgcG9zaXRpdmUgaW5hdWd1cmF0aW9uIHNwZWVjaCwgYW5kIHByZXNpZGVudHMgd2hvIHVzZSBsb25nZXIgc2VudGVuY2VzIHRlbmQgdG8gdXNlIGZld2VyIG5lZ2F0aXZlIHdvcmRzLgoKIyMgUGFydCAzLjQgRGF0YSBBbmFseXRpY3M6IFRvcGljIE1vZGVsaW5nCk5vdywgd2UgZm9jdXMgb24gdW5zdXBlcnZpc2Ugc3R1ZHkgb2YgdGhlIHNwZWVjaGVzLiBXZSBhcHBseSB0b3BpYyBtb2RlbGluZyBpbnRvIGFsbCB0aGUgaW5hdWd1cmF0aW9uIHNwZWVjaGVzIHRvIGZpbmQgdGhlIGNvbW1vbiB0b3BpY3MgaW4gYW1vbmcgdGhlIHNwZWVjaGVzLiBXZSB0aGVuIGNhdGVnb3JpemUgZWFjaCBzcGVlY2ggaW50byBhIHRvcGljIHRoYXQgaXQgaXMgbW9zdGx5IGxpa2VseSB0byBiZS4KClRvIGRvIHNvLCB3ZSBmaXJzdCBuZWVkIHRvIGFwcGx5IG5hdHVyYWwgbGFuZ3VhZ2UgcHJvY2Vzc2luZyB0byBvdXIgZGF0YSB0byByZW1vdmUgc29tZSB1bm5lY2Vzc2FyeSBjb250ZW50LCBzdWNoIGFzIG51bWJlciwgZXh0cmEgc3BhY2VzLCBhbmQgbWVhbmluZ2xlc3Mgd29yZHMuIFdlIGFsc28gc3RlbSB0aGUgZG9jdW1lbnQsIHdoaWNoIG9ubHkgdGhlIHN0ZW0gcGFydCBvZiB0aGUgd29yZCB3aWxsIGJlIHJlbWFpbmVkLiBGb3IgZXhhbXBsZSwgJ3N1cHBsaWVkJyBhbmQgJ3N1cHBsaWVzJyBib3RoIGJlY29tZSAnc3VwcGxpJy4KYGBge3IsIGluY2x1ZGU9RiwgZWNobz1GfQpjb3JwdXMubGlzdD1zZW50ZW5jZS5saXN0WzI6KG5yb3coc2VudGVuY2UubGlzdCktMSksIF0Kc2VudGVuY2UucHJlPXNlbnRlbmNlLmxpc3Qkc2VudGVuY2VzWzE6KG5yb3coc2VudGVuY2UubGlzdCktMildCnNlbnRlbmNlLnBvc3Q9c2VudGVuY2UubGlzdCRzZW50ZW5jZXNbMzoobnJvdyhzZW50ZW5jZS5saXN0KS0xKV0KY29ycHVzLmxpc3Qkc25pcGV0cz1wYXN0ZShzZW50ZW5jZS5wcmUsIGNvcnB1cy5saXN0JHNlbnRlbmNlcywgc2VudGVuY2UucG9zdCwgc2VwPSIgIikKcm0ucm93cz0oMTpucm93KGNvcnB1cy5saXN0KSlbY29ycHVzLmxpc3Qkc2VudC5pZD09MV0Kcm0ucm93cz1jKHJtLnJvd3MsIHJtLnJvd3MtMSkKY29ycHVzLmxpc3Q9Y29ycHVzLmxpc3RbLXJtLnJvd3MsIF0KCmRvY3MgPC0gQ29ycHVzKFZlY3RvclNvdXJjZShjb3JwdXMubGlzdCRzbmlwZXRzKSkKd3JpdGVMaW5lcyhhcy5jaGFyYWN0ZXIoZG9jc1tbc2FtcGxlKDE6bnJvdyhjb3JwdXMubGlzdCksIDEpXV0pKQpgYGAKYGBge3IsIGluY2x1ZGU9RiwgZWNobz1GfQojcmVtb3ZlIHBvdGVudGlhbGx5IHByb2JsZW1hdGljIHN5bWJvbHMKZG9jcyA8LXRtX21hcChkb2NzLGNvbnRlbnRfdHJhbnNmb3JtZXIodG9sb3dlcikpCndyaXRlTGluZXMoYXMuY2hhcmFjdGVyKGRvY3NbW3NhbXBsZSgxOm5yb3coY29ycHVzLmxpc3QpLCAxKV1dKSkKCiNyZW1vdmUgcHVuY3R1YXRpb24KZG9jcyA8LSB0bV9tYXAoZG9jcywgcmVtb3ZlUHVuY3R1YXRpb24pCndyaXRlTGluZXMoYXMuY2hhcmFjdGVyKGRvY3NbW3NhbXBsZSgxOm5yb3coY29ycHVzLmxpc3QpLCAxKV1dKSkKCiNTdHJpcCBkaWdpdHMKZG9jcyA8LSB0bV9tYXAoZG9jcywgcmVtb3ZlTnVtYmVycykKd3JpdGVMaW5lcyhhcy5jaGFyYWN0ZXIoZG9jc1tbc2FtcGxlKDE6bnJvdyhjb3JwdXMubGlzdCksIDEpXV0pKQoKI3JlbW92ZSBzdG9wd29yZHMKZG9jcyA8LSB0bV9tYXAoZG9jcywgcmVtb3ZlV29yZHMsIHN0b3B3b3JkcygiZW5nbGlzaCIpKQp3cml0ZUxpbmVzKGFzLmNoYXJhY3Rlcihkb2NzW1tzYW1wbGUoMTpucm93KGNvcnB1cy5saXN0KSwgMSldXSkpCgojcmVtb3ZlIHdoaXRlc3BhY2UKZG9jcyA8LSB0bV9tYXAoZG9jcywgc3RyaXBXaGl0ZXNwYWNlKQp3cml0ZUxpbmVzKGFzLmNoYXJhY3Rlcihkb2NzW1tzYW1wbGUoMTpucm93KGNvcnB1cy5saXN0KSwgMSldXSkpCgojU3RlbSBkb2N1bWVudApkb2NzIDwtIHRtX21hcChkb2NzLHN0ZW1Eb2N1bWVudCkKd3JpdGVMaW5lcyhhcy5jaGFyYWN0ZXIoZG9jc1tbc2FtcGxlKDE6bnJvdyhjb3JwdXMubGlzdCksIDEpXV0pKQpgYGAKClRoZW4sIHdlIGNyZWF0ZSBhIGJpZyBvZiB3b3Jkcywgd2hpY2ggaXMgYSBtYXRyaXggc2hvdyBpbiBhIGR1bW15IHZhcmlhYmxlIGZvcm1hdC4KYGBge3J9CmR0bSA8LSBEb2N1bWVudFRlcm1NYXRyaXgoZG9jcykKI2NvbnZlcnQgcm93bmFtZXMgdG8gZmlsZW5hbWVzI2NvbnZlcnQgcm93bmFtZXMgdG8gZmlsZW5hbWVzCnJvd25hbWVzKGR0bSkgPC0gcGFzdGUoY29ycHVzLmxpc3QkdHlwZSwgY29ycHVzLmxpc3QkRmlsZSwKICAgICAgICAgICAgICAgICAgICAgICBjb3JwdXMubGlzdCRUZXJtLCBjb3JwdXMubGlzdCRzZW50LmlkLCBzZXA9Il8iKQoKcm93VG90YWxzIDwtIGFwcGx5KGR0bSAsIDEsIHN1bSkgI0ZpbmQgdGhlIHN1bSBvZiB3b3JkcyBpbiBlYWNoIERvY3VtZW50CgpkdG0gIDwtIGR0bVtyb3dUb3RhbHM+IDAsIF0KY29ycHVzLmxpc3Q9Y29ycHVzLmxpc3Rbcm93VG90YWxzPjAsIF0KYGBgCgpOb3csIHdlIGFwcGx5IExEQSB0b3BpYyBtb2RlbGluZyBpbnRvIG91ciBiYWcgb2Ygd29yZHMuCmBgYHtyfQojU2V0IHBhcmFtZXRlcnMgZm9yIEdpYmJzIHNhbXBsaW5nCmJ1cm5pbiA8LSA0MDAwICMgcmVtb3ZpbmcgdGhlIGZpcnN0IDQwMDAgc2FtcGxlcwppdGVyIDwtIDIwMDAKdGhpbiA8LSA1MDAgI2Nob29zZSA1MDB0aCBpbiBlYWNoIHJvdW5kLCBkcm9wIHRoZSA0OTkgb3RoZXJzCiM1MDAgaXMgdXNpbmcgZXZlcnkgNTAwdGggZ3Vlc3MgYmVjYXVzZSBlYWNoIGd1ZXNzIGlzIGJhc2VkIG9uIGl0cyBwcmV2aW91cyBndWVzcy4gc28gbiB0byBuKzEgd29uJ3QgaGF2ZSBtdWNoIGRpZmZlcmVuY2UgYnV0IG4gYW5kIG4rNTAwdGggZ3Vlc3Mgd291bGQgYmUgbXVjaCBkaWZmZXJlbmNlIGFuZCBpbnRlbGxpZ2VudApzZWVkIDwtbGlzdCgyMDAzLDUsNjMsMTAwMDAxLDc2NSkKbnN0YXJ0IDwtIDUKYmVzdCA8LSBUUlVFCgojTnVtYmVyIG9mIHRvcGljcwprIDwtIDEwCgojUnVuIExEQSB1c2luZyBHaWJicyBzYW1wbGluZwpsZGFPdXQgPC1MREEoZHRtLCBrLCBtZXRob2Q9IkdpYmJzIiwgY29udHJvbD1saXN0KG5zdGFydD1uc3RhcnQsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VlZCA9IHNlZWQsIGJlc3Q9YmVzdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ1cm5pbiA9IGJ1cm5pbiwgaXRlciA9IGl0ZXIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpbj10aGluKSkKI3dyaXRlIG91dCByZXN1bHRzCiNkb2NzIHRvIHRvcGljcwpsZGFPdXQudG9waWNzIDwtIGFzLm1hdHJpeCh0b3BpY3MobGRhT3V0KSkKdGFibGUoYygxOmssIGxkYU91dC50b3BpY3MpKQp3cml0ZS5jc3YobGRhT3V0LnRvcGljcyxmaWxlPXBhc3RlKCJ+L0Rlc2t0b3AvQ29sdW1iaWEvU2VtZXN0ZXIgMi9BRFMvUHJvamVjdDEvd2syLVRleHRNaW5pbmcvb3V0L0xEQUdpYmJzIixrLCJEb2NzVG9Ub3BpY3MuY3N2IikpCgojdG9wIDIwIHRlcm1zIGluIGVhY2ggdG9waWMKbGRhT3V0LnRlcm1zIDwtIGFzLm1hdHJpeCh0ZXJtcyhsZGFPdXQsMjApKQp3cml0ZS5jc3YobGRhT3V0LnRlcm1zLGZpbGU9cGFzdGUoIn4vRGVza3RvcC9Db2x1bWJpYS9TZW1lc3RlciAyL0FEUy9Qcm9qZWN0MS93azItVGV4dE1pbmluZy9vdXQvTERBR2liYnMiLGssIlRvcGljc1RvVGVybXMuY3N2IikpCgojcHJvYmFiaWxpdGllcyBhc3NvY2lhdGVkIHdpdGggZWFjaCB0b3BpYyBhc3NpZ25tZW50CnRvcGljUHJvYmFiaWxpdGllcyA8LSBhcy5kYXRhLmZyYW1lKGxkYU91dEBnYW1tYSkKdG9waWNQcm9iYWJpbGl0aWVzJG1heCA9IGFwcGx5KHRvcGljUHJvYmFiaWxpdGllcywgMSwgbWF4KQp3cml0ZS5jc3YodG9waWNQcm9iYWJpbGl0aWVzLGZpbGU9cGFzdGUoIn4vRGVza3RvcC9Db2x1bWJpYS9TZW1lc3RlciAyL0FEUy9Qcm9qZWN0MS93azItVGV4dE1pbmluZy9vdXQvTERBR2liYnMiLGssIlRvcGljUHJvYmFiaWxpdGllcy5jc3YiKSkKCiMgdXNlIGJldGEgZGlzdHJpYnV0aW9uCnRlcm1zLmJldGE9bGRhT3V0QGJldGEKdGVybXMuYmV0YT1zY2FsZSh0ZXJtcy5iZXRhKQp0b3BpY3MudGVybXM9TlVMTApmb3IoaSBpbiAxOmspewogIHRvcGljcy50ZXJtcz1yYmluZCh0b3BpY3MudGVybXMsIGxkYU91dEB0ZXJtc1tvcmRlcih0ZXJtcy5iZXRhW2ksXSwgZGVjcmVhc2luZyA9IFRSVUUpWzE6N11dKQp9CmBgYAoKQWZ0ZXIgd2Ugb2J0YWluIHRoZSBsaXN0IG9mIHRvcGljLCB3ZSBsb29rIGF0IHRoZSB3b3JkIGVhY2ggdG9waWMgY29udGFpbnMgYW5kIGdpdmUgYSB0aXRsZSB0byBlYWNoIHRvcGljLiBIZXJlLCB3ZSBzZXQgdGhlIHRpdGxlIG5hbWUgaW50byBhIHZlY3RvciwgdG9waWNzLmhhc2guCmBgYHtyfQp0b3BpY3MuaGFzaCA9IGMoJ2dvdmVybm1lbnQnLCdhbWVyaWNhbiBkcmVhbScsICdlY29ub215JywgJ2ZhaXRoJywgJ2FudGljaXBhdGUnLCAncGVvcGxlJywgJ2NpdmlsIHJpZ2h0JywgJ3BhdHJpb3QnLCAnbGVnaXN0cmF0aW9uJywgJ3BlYWNlJywgJ21heCcpCmNvcnB1cy5saXN0JGxkYXRvcGljPWFzLnZlY3RvcihsZGFPdXQudG9waWNzKQojY29ycHVzLmxpc3QkbGRhaGFzaD10b3BpY3MuaGFzaFtsZGFPdXRdCgpjb2xuYW1lcyh0b3BpY1Byb2JhYmlsaXRpZXMpPXRvcGljcy5oYXNoCmNvcnB1cy5saXN0LmRmPWNiaW5kKGNvcnB1cy5saXN0LCB0b3BpY1Byb2JhYmlsaXRpZXMpCmBgYAoKTm93LCB3ZSBwbG90IG91ciBkYXRhIGludG8gYSBoZWF0bWFwIHRvIHNlZSBpZiBzb21lIHByZXNpZGVudHMgc2hhcmUgdmVyeSBzaW1pbGFyIHRvcGljcy4gSW4gYSBoZWF0IG1hcCwgdGhlIHNhbWUgY29sb3IgbWVhbnMgcmVwcmVzZW50IHRoZSBzYW1lIHByb2JhYmlsaXR5LiBUaGUgcmVkZGVyIHRoZSBjb2xvciBpcyBtZWFucyB0aGUgaGlnaGVyIHRoZSBwcm9iYWJpbGl0eS4KYGBge3J9CnBhcihtYXI9YygxLDEsMSwxKSkKdG9waWMuc3VtbWFyeT10YmxfZGYoY29ycHVzLmxpc3QuZGYpJT4lCiAgICAgICAgICAgICAgZmlsdGVyKHR5cGUlaW4lYygnaW5hdWcnKSwgRmlsZSVpbiVjKGRlbW9jcmF0aWMsIHJlcHVibGljYW4pKSU+JQogICAgICAgICAgICAgIHNlbGVjdChGaWxlLCBnb3Zlcm5tZW50OnBlYWNlKSU+JQogICAgICAgICAgICAgIGdyb3VwX2J5KEZpbGUpJT4lCiAgICAgICAgICAgICAgc3VtbWFyaXNlX2VhY2goZnVucyhtZWFuKSkKdG9waWMuc3VtbWFyeT1hcy5kYXRhLmZyYW1lKHRvcGljLnN1bW1hcnkpCnJvd25hbWVzKHRvcGljLnN1bW1hcnkpPXRvcGljLnN1bW1hcnlbLDFdCgpoZWF0bWFwLjIoYXMubWF0cml4KHRvcGljLnN1bW1hcnlbLHRvcGljLnBsb3QrMV0pLCAKICAgICAgICAgIHNjYWxlID0gImNvbHVtbiIsIGtleT1GLCAKICAgICAgICAgIGNvbCA9IGJsdWVyZWQoMTAwKSwKICAgICAgICAgIGNleFJvdyA9IDAuOSwgY2V4Q29sID0gMC45LCBtYXJnaW5zID0gYyg4LCA4KSwKICAgICAgICAgIHRyYWNlID0gIm5vbmUiLCBkZW5zaXR5LmluZm8gPSAibm9uZSIpCmBgYApGcm9tIHRoZSBoZWF0bWFwLCB3ZSBzYXcgRHdpZ2h0IEQgRWlzZW5ob3dlcihLb3JlYW4gV2FyKSwgSGFycnkgUyBUcnVtYW4oV1cgSUkpLCBXYXJyZW4gRyBIYXJkaW5nIChyaWdodCBhZnRlciBXVyBJKSwgYW5kIENhbGJpbiBDb29saWRnZShwb3N0IFdXIEkpIG1lbnRpb25lZCB0aGUgdG9waWMgb2YgJ3BlYWNlJyBpbiB0aGVpciBpbmF1Z3VyYXRpb24gc3BlZWNoZXMuIEFzIEkgYW5hbHl6ZWQgbW9yZSBhYm91dCBlYWNoIG9mIHRoZWlyIHByZXNpZGVuY3ksIEkgZm91bmQgUHJlc2lkZW50IEVpc2VuaG93ZXIgd2FzIGluIHRoZSBvZmZpY2UgZHVyaW5nIEtvcmVhbiBXYXIsIFByZXNpZGVudCBUcnVtYW4gd2FzIGVsZWN0ZWQgbmVhciB0aGUgdmVyeSBlbmQgb2YgV29ybGQgV2FyIElJLCBQcmVzaWRlbnQgSGFyZGluZyB3YXMgaW4gdGhlIG9mZmljZSByaWdodCBhZnRlciBXb3JsZCBXYXIgSSwgYW5kIFByZXNpZGVudCBDb29saWRnZSB3YXMgaW4gdGhlIG9mZmljZSBkdXJpbmcgdGhlIHBvc3QgV29ybGQgV2FyIEkgcGVyaW9kLiBUaGlzIG1heSBleHBsYWluIHdoeSB0aGV5IGZvY3VzIHRvICdwZWFjZScgcmVsYXRlZCB0b3BpYy4KCldpbGxpYW0gSG93YXJkIFRhZnQsIEdyb3ZlciBDbGV2ZWxhbmQgSUksIFVseXNzZXMgUyBHcmFudCwgYW5kIFdpbGxpYW0gTWNraW5sZXkgbWVudGlvbmVkIHRoZSB0b3BpYyBvZiAnZWNvbm9teScuIEFzIHdlIHJlc2VhcmNoZWQgbW9yZSBhYm91dCB0aGVpciBwcmVzaWRlbnRpYWwgcG9saWN5IGFuZCBoaXN0b3J5LCB3ZSBmb3VuZCBQcmVzaWRlbnQgVGFmdCB3YXMgaW52b2x2ZWQgaW4gZG9sbGFyeSBkaXBsb21hY3ksIFByZXNpZGVudCBDbGV2ZWxhbmQgd2FzIG92ZXJ3aGVsbWVkIGJ5IG5hdGlvbidzIGVjb25vbWljIGRpc2FzdGVycy1kZXByZXNzaW9uLCBQcmVzaWRlbnQgR3JhbnQgd2FzIGluIHRoZSBvZmZpY2UgZHVyaW5nIHRoZSBHaWxkZWQgQWdlLCBhIG1hc3NpdmUgaW5kdXN0cmlhbCBncm93dGgsIGFuZCBQcmVzaWRlbnQgTWNraW5sZXkgbGVkIEFtZXJpY2FuIHRocm91Z2ggdGhlIHJhcGlkIGVjb25vbWljIGdyb3d0aC4gVGhlc2UgbWF5IGV4cGxhaW4gdGhlIGV4cHJlc3Npb24gb2YgJ2Vjb25vbXknIHJlbGF0ZWQgdG9waWMgaW4gdGhlaXIgaW5hdWd1cmF0aW9uIHNwZWVjaGVzLgoKTm93LCBsZXQncyBpbnZlc3RpZ2F0ZSB0aGUgdG9waWMgZGlmZmVyZW5jZSBpbiBiZXR3ZWVuIHJlcHVibGljYW4gYW5kIGRlbW9jcmF0aWMuCmBgYHtyfQpkZW0ucmVwLnRhYmxlID0gdGFibGUoY29ycHVzLmxpc3QuZGZbLGMoJ1BhcnR5JywnbGRhdG9waWMnKV0pW2MoMSw0KSxdCmJhcnBsb3QoZGVtLnJlcC50YWJsZSwgYmVzaWRlID0gVCwgY29sPWMoMiw1KSwgeGxhYiA9ICdUb3BpYycpCmxlZ2VuZCgndG9wcmlnaHQnLCBsZWdlbmQgPSBjKCdEZW1vY3JhdGljJywnUmVwdWJsaWNhbicpLCBmaWxsPWMoMiw1KSkKYGBgCkFzIHdlIGNhbiBzZWUgZnJvbSBhYm92ZSwgcmVwdWJsaWNhbiBwcmVzaWRlbnRzIHRlbmQgdG8gY292ZXIgbW9yZSBhYm91dCB0b3BpYyAzLCA5LCBhbmQgMTAsIHdoaWNoIGFyZSAnZWNvbm9teScsICdsZWdpc3RyYXRpb24nLCBhbmQgJ3BlYWNlJyB3aGlsZSBkZW1vY3JhdGljIHByZXNpZGVudHMgdGVuZCB0byBjb3ZlciBtb3JlIGFib3V0IHRvcGljIDEgYW5kIDgsIHdoaWNoIGFyZSAnZ292ZXJubWVudCcgYW5kICdwYXRyaW90Jy4KCk5vdywgbGV0J3MgaW52ZXN0aWdhdGUgb24gdGhlIHRvcGljIHRoYXQgcHJlc2lkZW50cyB3aG8gYXR0ZW5kZWQgZ3JhZHVhdGUgc2Nob29sIHRlbmQgdG8gY292ZXIuCmBgYHtyfQp6Lm5vLmdyYWQgPSBjb3JwdXMubGlzdC5kZltjKG5vLmdyYWQuZGVtLnNlbnRlbmNlLmluZCwgbm8uZ3JhZC5yZXAuc2VudGVuY2UuaW5kKSxjKCdsZGF0b3BpYycpXQoKZ3JhZC5zZW50ZW5jZS5pbmQgPSAoMTpucm93KGNvcnB1cy5saXN0LmRmKSlbLWMobm8uZ3JhZC5kZW0uc2VudGVuY2UuaW5kLG5vLmdyYWQucmVwLnNlbnRlbmNlLmluZCldWzY5Mjpucm93KGNvcnB1cy5saXN0LmRmKV0KCnouZ3JhZCA9IGNvcnB1cy5saXN0LmRmW2dyYWQuc2VudGVuY2UuaW5kLGMoJ2xkYXRvcGljJyldCgp6LmdyYWQudGFibGUgPSB0YWJsZSh6LmdyYWQpCnoubm8uZ3JhZC50YWJsZSA9IHRhYmxlKHoubm8uZ3JhZCkKZGVtLnJlcC50YWJsZSA9IGFzLmRhdGEuZnJhbWUoY2JpbmQoei5ncmFkLnRhYmxlLCB6Lm5vLmdyYWQudGFibGUpKQpkZW0ucmVwLnRhYmxlCmBgYApUaGUgbGVmdCB0YWJsZSBzaG93cyB0aGUgbnVtYmVyIG9mIHNlbnRlbmNlcyBpbiBlYWNoIHRvcGljIG9mIHByZXNpZGVudHMgd2hvIGF0dGVuZCBncmFkdWF0ZSBzY2hvb2wgd2hpbGUgdGhlIHJpZ2h0IHRhYmxlIHNob3dzIHRoYXQgb2YgcHJlc2lkZW50cyB3aG8gZGlkIG5vdCBhdHRlbmQgZ3JhdWRhdGUgc2Nob29sLiBBcyB3ZSBjYW4gc2VlIGZyb20gdGhlIHRhYmxlIGFib3ZlLCBwcmVzaWRlbnRzIHdobyBhdHRlbmRlZCBncmFkdWF0ZSBzY2hvb2wgdGVuZCB0byBjb3ZlciB0b3BpYyAyIGFuZCA1IGluIHRoZWlyIGluYXVndXJhdGlvbiBzcGVlY2gsIHdoaWNoIGFyZSAnYW1lcmljYW4gZHJlYW0nIGFuZCAnYW50aWNpcGF0ZScgd2hpbGUgcHJlc2lkZW50cyB3aG8gZGlkIG5vdCBhdHRlbmQgZ3JhZHVhdGUgc2Nob29sIHRlbmQgdG8gY292ZXIgdG9waWMgMywgNiwgYW5kIDksIHdoaWNoIGFyZSAnZWNvbm9teScsICdwZW9wbGUnLCBhbmQgJ2xlZ2lzdHJhdGlvbicuIFRoaXMgbWF5IHN1Z2dlc3QgcHJlc2lkZW50cyB3aG8gYXR0ZW5kZWQgZ3JhZHVhdGUgdGVuZCB0byBmb2N1cyBvbiB0aGUgZnV0dXJlIGFuZCBjb3JlIHZhbHVlIG9mIEFtZXJpY2Egd2hpbGUgdGhlIHByZXNpZGVudHMgd2hvIGRpZCBub3QgYXR0ZW5kIGdyYWR1YXRlIHNjaG9vbCB0ZW5kIHRvIGZvY3VzIG9uIG1vcmUgcHJhZ21hdGljIHRvcGljcy4KCk5vdywgbGV0J3MgcGVyZm9ybSBhIGNsdXN0ZXJpbmcgb24gcHJlc2lkZW50cyB3aG8gYXR0ZW5kZWQgZ3JhZHVhdGUgc2Nob29sIGFuZCB3aG8gZGlkIG5vdCBhdHRlbmQgZ3JhdWRhdGUgc2Nob29sLgpgYGB7cn0KcHJlc2lkLnN1bW1hcnk9dGJsX2RmKGNvcnB1cy5saXN0LmRmKSU+JQogIGZpbHRlcih0eXBlPT0iaW5hdWciLCBGaWxlJWluJSBzcGVlY2gubGlzdCRGaWxlW2MoZ3JhZC5hMTg5MC5pbmQsZ3JhZC5iMTg5MC5pbmQpXSklPiUKICBzZWxlY3QoRmlsZSwgZ292ZXJubWVudDpwZWFjZSklPiUKICBncm91cF9ieShGaWxlKSU+JQogIHN1bW1hcmlzZV9lYWNoKGZ1bnMobWVhbikpCgpwcmVzaWQuc3VtbWFyeT1hcy5kYXRhLmZyYW1lKHByZXNpZC5zdW1tYXJ5KQpyb3duYW1lcyhwcmVzaWQuc3VtbWFyeSk9YXMuY2hhcmFjdGVyKChwcmVzaWQuc3VtbWFyeVssMV0pKQprbS5yZXM9a21lYW5zKHNjYWxlKHByZXNpZC5zdW1tYXJ5WywtMV0pLCBpdGVyLm1heD0yMDAsCiAgICAgICAgICAgICAgNSkKZnZpel9jbHVzdGVyKGttLnJlcywgCiAgICAgICAgICAgICBzdGFuZD1ULCByZXBlbD0gVFJVRSwKICAgICAgICAgICAgIGRhdGEgPSBwcmVzaWQuc3VtbWFyeVssLTFdLAogICAgICAgICAgICAgc2hvdy5jbHVzdC5jZW50PUZBTFNFLCBtYWluID0gJ2dyYWQnKQoKCnByZXNpZC5zdW1tYXJ5PXRibF9kZihjb3JwdXMubGlzdC5kZiklPiUKICBmaWx0ZXIodHlwZT09ImluYXVnIiwgRmlsZSVpbiUgc3BlZWNoLmxpc3QkRmlsZVtjKG5vLmdyYWQuYTE4OTAuaW5kLG5vLmdyYWQuYjE4OTAuaW5kKV0pJT4lCiAgc2VsZWN0KEZpbGUsIGdvdmVybm1lbnQ6cGVhY2UpJT4lCiAgZ3JvdXBfYnkoRmlsZSklPiUKICBzdW1tYXJpc2VfZWFjaChmdW5zKG1lYW4pKQoKcHJlc2lkLnN1bW1hcnk9YXMuZGF0YS5mcmFtZShwcmVzaWQuc3VtbWFyeSkKcm93bmFtZXMocHJlc2lkLnN1bW1hcnkpPWFzLmNoYXJhY3RlcigocHJlc2lkLnN1bW1hcnlbLDFdKSkKa20ucmVzPWttZWFucyhzY2FsZShwcmVzaWQuc3VtbWFyeVssLTFdKSwgaXRlci5tYXg9MjAwLAogICAgICAgICAgICAgIDUpCmZ2aXpfY2x1c3RlcihrbS5yZXMsIAogICAgICAgICAgICAgc3RhbmQ9VCwgcmVwZWw9IFRSVUUsCiAgICAgICAgICAgICBkYXRhID0gcHJlc2lkLnN1bW1hcnlbLC0xXSwKICAgICAgICAgICAgIHNob3cuY2x1c3QuY2VudD1GQUxTRSwgbWFpbiA9ICdubyBncmFkJykKCgpgYGAKVGhlIGdyYXBoIGluIHRoZSByaWdodCBzaG93cyB0aGUgY2x1c3RlcmluZyBvZiBwcmVzaWRlbnRzIHdobyBkaWQgbm90IGF0dGVuZCBncmFkdWF0ZSBzY2hvb2wgYW5kIHRoZSBncmFwaCBpbiB0aGUgbGVmdCBzaG93cyB0aGF0IG9mIHByZXNpZGVudHMgd2hvIGF0dGVuZGVkIGdyYWR1YXRlIHNjaG9vbC4gQXMgd2Ugb2JzZXJ2ZSB0aGUgY2x1c3RlciBwbG90IGFib3ZlLCB3ZSBub3RpY2UgcHJlc2lkZW50IGZyb20gdGhlIHNhbWUgcGFydHkgdGVuZCB0byBmb3JtIGl0J3Mgb3duIGNsdXN0ZXIuIEZvciBleGFtcGxlLCBpbiAnbm8gZ3JhZCcgY2x1c3RlciwgYWxsIHByZXNpZGVudHMgaW4gY2x1c3RlciAzIGFyZSBkZW1vY3JhdGljIHdoaWxlIGFsbCBwcmVzaWRlbnRzIGluIGNsdXN0ZXIgNSBhcmUgcmVwdWJsaWNhbi4gCgpUaGVuLCB3ZSB0aGluayBpZiB0aGUgcHJlc2lkZW50cyBhcmUgY2x1c3RlcmVkIHRvZ2V0aGVyLCB0aGlzIG1lYW5zIHRoZXkgZ2F2ZSBzaW1pbGFyIGluYXVndXJhdGlvbiBzcGVlY2hlcywgd2hpY2ggc3VnZ2VzdHMgdGhleSBtaWdodCBhbHNvIHNoYXJlIHNpbWlsYXIgcG9saWNpZXMuIFRoZXJlZm9yZSwgaWYgYW4gQW1lcmljYW4gc3VwcG9ydHMgb25lIG9mIHRoZSBwcmVzaWRlbnRzIGluIHRoZSBjbHVzdGVyLCBoZS9zaGUgbWF5IGFzIHdlbGwgc3VwcG9ydHMgYW5vdGhlciBwcmVzaWRlbnQgaW4gdGhlIHNhbWUgY2x1c3Rlci4gSGVuY2UsIHdlIGZvdW5kIGEgZGF0YXNldCBmcm9tIFdpa2lwZWRpYSB0aGF0IGNvbnRhaW5zIGFwcHJvdmFsIHJhdGUgb2YgYWxsIHByZXNpZGVudHMgc2luY2UgMTkzNy4gKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL1VuaXRlZF9TdGF0ZXNfcHJlc2lkZW50aWFsX2FwcHJvdmFsX3JhdGluZykKYGBge3J9CnByZXNpZC5zdW1tYXJ5PXRibF9kZihjb3JwdXMubGlzdC5kZiklPiUKICBmaWx0ZXIodHlwZT09ImluYXVnIiwgRmlsZSVpbiUgc3BlZWNoLmxpc3QkRmlsZVszNzo1OF0pJT4lCiAgc2VsZWN0KEZpbGUsIGdvdmVybm1lbnQ6cGVhY2UpJT4lCiAgZ3JvdXBfYnkoRmlsZSklPiUKICBzdW1tYXJpc2VfZWFjaChmdW5zKG1lYW4pKQoKcHJlc2lkLnN1bW1hcnk9YXMuZGF0YS5mcmFtZShwcmVzaWQuc3VtbWFyeSkKcm93bmFtZXMocHJlc2lkLnN1bW1hcnkpPWFzLmNoYXJhY3RlcigocHJlc2lkLnN1bW1hcnlbLDFdKSkKa20ucmVzPWttZWFucyhzY2FsZShwcmVzaWQuc3VtbWFyeVssLTFdKSwgaXRlci5tYXg9MjAwLAogICAgICAgICAgICAgIDUpCmZ2aXpfY2x1c3RlcihrbS5yZXMsIAogICAgICAgICAgICAgc3RhbmQ9VCwgcmVwZWw9IFRSVUUsCiAgICAgICAgICAgICBkYXRhID0gcHJlc2lkLnN1bW1hcnlbLC0xXSwKICAgICAgICAgICAgIHNob3cuY2x1c3QuY2VudD1GQUxTRSwgbWFpbiA9ICdwcmVzaWRlbnRzIGFmdGVyIDE5MzcnKQpgYGAKRnJvbSB0aGUgZ3JhcGgsIHdlIGxvb2sgYXQgY2x1c3RlciAyLCB3aGVyZSB0aGVyZSBhcmUgdGhyZWUgcHJlc2lkZW50cyBpbmNsdWRpbmcgUmljaGFyZCBOaXhvbiwgV2lsbGlhbSBDbGludG9uLCBhbmQgQmFyYWNrIE9iYW1hLiBBY2NvcmRpbmcgdG8gdGhlIGhpc3RvcmljYWwgYXBwcm92YWwgcmF0ZSBmcm9tIFdpa2lwZWRpYSwgUHJlaXNkZW50IE5peG9uIGhhcyBhbiBhdmVyYWdlIGFwcHJvdmFsIHJhdGUgb2YgNDkuMSwgUHJlc2lkZW50IENsaW50b24gaGFzIGFuIGF2ZXJhZ2UgYXBwcm92YWwgcmF0ZSBvZiA1NS4xLCBQcmVzaWRlbnQgT2JhbWEgaGFzIGFuIGF2ZXJhZ2UgYXBwcm92YWwgcmF0ZSBvZiA0Ny45LiBBbHNvLCBpZiB3ZSBsb29rIGF0IGNsdXN0ZXIgNCwgd2hlcmUgdGhlcmUgYXJlIGZvdXIgcHJlc2lkZW50cyBpbmNsdWRpbmcgR2VvcmdlIEJ1c2gsIEZyYW5rbGluIFJvb3NldmVsdCwgTHluZG9uIEpvaG5zb24sIGFuZCBEb25hbGQgVHJ1bXAuIEFzIFByZXNpZGVudCBUcnVtcCBoYXMganVzdCBiZWVuIGludG8gYW4gb2ZmaWNlIGZvciBhIHllYXIsIHdlIHdpbGwgYWNjb3VudCBoaW0gaW50byB0aGlzIGFwcHJvdmFsIHJhdGUgYW5hbHlzaXMuIFByZXNpZGVudCBKb2huc29uIGhhcyBhbiBhdmVyYWdlIGFwcHJvdmFsIHJhdGUgb2YgNTUuMSwgUHJlc2lkZW50IEJ1c2ggaGFzIGFuIGF2ZXJhZ2UgYXBwcm92YWwgcmF0ZSBvZiA2MC45LCBhbmQgUHJlc2lkZW50IFJvb3NldmVsdCBoYXMgYW4gYXZlcmFnZSBhcHByb3ZhbCByYXRlIG9mIDYzLiBUaGVzZSByZXN1bHRzIG1hdGNoIG91ciBoeXBvdGhlc2lzIG9mIHByZXNpZGVudHMgaGF2ZSBzaW1pbGFyIGluYXVndXJhdGlvbiBzcGVlY2ggdGVuZCB0byBoYXZlIHNpbWlsYXIgYXBwcm92YWwgcmF0ZS4gQnV0IGZ1cnRoZXIgYW5hbHlzaXMgaXMgcmVxdWlyZWQgYXMgdGhlIGNvbGxlY3Rpb24gb2YgYXBwcm92YWwgcmF0ZSBzdGFydGVkIGluIDE5MzcgbWVhbmluZyB3ZSBvbmx5IGhhdmUgdmVyeSBsaW1pdGVkIGRhdGEuCgpTdW1tYXJ5OgpJbiBwYXJ0IDMuNCwgd2UgYXBwbGllZCB0b3BpYyBtb2RlbGluZyBpbnRvIHRoZSBpbmF1Z3VyYXRpb24gc3BlZWNoZXMsIHdlIGZvdW5kIHByZXNpZGVudHMgZnJvbSBkaWZmZXJlbnRzIHBhcnRpZXMgdGVuZCB0byBmb2N1cyBvbiBkaWZmZXJlbnQgdG9waWNzIGFuZCBwcmVzaWRlbnRzIHdobyBhdHRlbmRlZCB0byBncmFkdWF0ZSBzY2hvb2wgYWxzbyB0ZW5kIHRvIGZvY3VzIG9uIGRpZmZlcmVudCB0b3BpY3MuIEZ1cnRoZXJtb3JlLCB3ZSBmb3VuZCBwcmVzaWRlbnRzIGluIHRoZSBzYW1lIGNsdXN0ZXIgdGVuZCB0byBiZSBpbiB0aGUgc2FtZSBwYXJ0eSBhbmQgaGF2ZSB0aGUgc2ltaWxhciBhcHByb3ZhbCByYXRlLgoKIyMgQ29uY2x1c2lvbgpJbiBjb25jbHVzaW9uLCBpbiB0aGlzIHN0dWR5LCB3ZSBzaG93ZWQgdGhhdCBSZXB1YmxpY2FuIFByZXNpZGVudHMgdGVuZCB0byB1c2Ugc2hvcnRlciBzZW50ZW5jZXMgYXMgY29tcGFyZWQgdG8gRGVtb2NyYXRpYyBQcmVzaWRlbnRzLCBhbmQgdGhpcyBtYXkgZHVlIHRvIHRoZSBmYWN0IHRoYXQgdGhlcmUgYXJlIGZld2VyIFJlcHVibGljYW4gUHJlc2lkZW50cyB3aG8gYXR0ZW5kZWQgZ3JhZHVhdGUgc2Nob29sLiBXZSBhbHNvIHNob3dlZCB0aGF0IFByZXNpZGVudHMgd2hvIGF0dGVuZGVkIGdyYWR1YXRlIHNjaG9vbCB0ZW5kIHRvIHVzZSBtb3JlIHBvc2l0aXZlIHdvcmRzIGluIHRoZWlyIGluYXVndXJhdGlvbiBzcGVlY2ggd2hpbGUgcHJlc2lkZW50cyB3aG8gdXNlIGxvbmdlciBzZW50ZW5jZXMgdGVuZCB0byB1c2UgZmV3ZXIgbmVnYXRpdmUgd29yZHMuIEZ1cnRoZXJtb3JlLCB3ZSBmb3VuZCB0aGF0IGdvaW5nIHRvIGdyYWR1YXRlIHNjaG9vbCBiZWZvcmUgMTg5MCBtYXkgaGF2ZSBhIHN0cm9uZ2VyIGltcGFjdCBpbiBzZW50ZW5jZSBsZW5ndGggYXMgZ3JhZHVhdGUgc2Nob29sIHdlcmUgaGFyZGVyIHRvIGdldCBpbiBiZWZvcmUgMTg5MC4gRmluYWxseSwgcHJlc2lkZW50cyBmcm9tIHRoZSBzYW1lIHBhcnR5IHRlbmQgdG8gY292ZXIgc2ltaWxhciB0b3BpY3MgaW4gdGhlaXIgaW5hdWd1cmF0aW9uIHNwZWVjaCwgYW5kIHByZXNpZGVudHMgd2hvIG1lbnRpb24gc2ltaWxhciB0b3BpY3MgaW4gdGhlaXIgaW5hdWd1cmF0aW9uIHNwZWVjaCBtYXkgc2hhcmUgc2ltaWxhciBhcHByb3ZhbCByYXRlLiAKCiMjIFJlZmVyZW5jZQpodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9Vbml0ZWRfU3RhdGVzX3ByZXNpZGVudGlhbF9hcHByb3ZhbF9yYXRpbmcKaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvTGlzdF9vZl9wcmVzaWRlbnRzX29mX3RoZV9Vbml0ZWRfU3RhdGVzX2J5X2FnZQpodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9IaXN0b3J5X29mX2hpZ2hlcl9lZHVjYXRpb25faW5fdGhlX1VuaXRlZF9TdGF0ZXMKaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvTGlzdF9vZl9QcmVzaWRlbnRzX29mX3RoZV9Vbml0ZWRfU3RhdGVzX2J5X2VkdWNhdGlvbgpodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9MaXN0X29mX1ByZXNpZGVudHNfb2ZfdGhlX1VuaXRlZF9TdGF0ZXMKCgo=